Lesson content
Read, practise, then check your understanding
A declaration tells callers a function’s name, parameter types, and return type. A definition supplies its body. Place stable declarations in headers and definitions in source files; include guards or #pragma once prevent repeated header contents.
#include <string_view>
[[nodiscard]] int factorial(int n) {
if (n < 0) return 0;
if (n <= 1) return 1;
return n * factorial(n - 1);
}
void greet(std::string_view name, int times = 1);
Pass small cheap types by value. Use const T& for a large read-only object, T& for a required mutable output, and T* when absence is meaningful. Never return a pointer or reference to a destroyed local object.
Recursion and overloading
Recursion needs a base case and progress toward it. Deep recursion consumes stack space, so an iterative solution may be safer. Overloads share a name but differ in parameter lists; return type alone cannot distinguish them. Default arguments are substituted at the call site and should normally appear in one visible declaration.
inline and constexpr
inline primarily permits identical definitions in multiple translation units; it does not force machine-code inlining. Define short templates and constexpr functions in headers because their definitions must be visible where instantiated or evaluated.
constexpr int square(int value) noexcept {
return value * value;
}
static_assert(square(6) == 36);
Keep functions focused, name contracts clearly, minimize hidden global effects, and use [[nodiscard]] when ignoring a result is probably a bug.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.