Basic Syntax
Constants and Literals
const, constexpr, and literal types
Interview: Modern C++ practices
Constants and Literals in C++
Modern C++ distinguishes heavily between runtime constants and compile-time constants. Evaluating expressions at compile time is a core optimization paradigm, allowing applications to minimize runtime footprint and overhead.
Const vs. Constexpr vs. Consteval
const (Runtime Const)
Promises that a variable cannot be modified after its initialization. The initialization value itself can be resolved at runtime (e.g., reading user inputs: const int input = readFromUser();).
constexpr (Compile-time Const)
Introduced in C++11. Indicates that the variable or function value is evaluated at compile time. It is implicitly const. Must be initialized using constant expressions.
consteval (Immediate Functions)
Introduced in C++20. Declares that a function must evaluate at compile time. It guarantees that no runtime function call instruction is generated. Calling a consteval function with a non-constant parameter is a compile-time error.
constinit (Global Constant Init)
Introduced in C++20. Guarantees that global variables are initialized at compile-time to prevent static initialization order fiasco (SIOF). Note: the variable itself remains modifiable at runtime.
Literals, Suffixes, and User-Defined Literals
C++ supports visual literal formatters like digit separators (1'000'000), binary literals (0b101010), and literal suffixes (ULL for unsigned long long, f for float). Advanced developers can define User-Defined Literals (UDL) to attach type meaning to raw suffixes (e.g. converting 3.4_km directly to meters).
Interview Corner
Q: What is the difference between const and constexpr?
A: const represents a read-only variable whose value is determined either at compile-time or runtime. constexpr is evaluated strictly at compile-time, allowing its value to be used as array sizes, template parameters, or case labels.
Q: What is the static initialization order fiasco (SIOF), and how does constinit solve it?
A: SIOF happens when a global variable in one translation unit depends on another global variable in another unit before it has been initialized. C++20's constinit guarantees that global constant expressions are fully initialized during compilation, eliminating SIOF initialization race conditions.
Common Pitfalls
- Assuming const is compile-time: Trying to declare array sizes using runtime constants:
int x; cin >> x; const int sz = x; int arr[sz];(leads to VLA compilation errors on strict compilers). - Overcomplicating constexpr functions: Writing functions with infinite recursion or massive loops. If compilation limits are exceeded, compilation errors will occur.
Best Practices
- Make variables
constexprwhenever their values are fully known at compile-time. - Use digit separators
1'000'000to format large integers for code readability. - Avoid old C-style preprocessor
#defineconstants; they have no type checking and ignore scope constraints.
Use Cases
Compile-Time Tables: Pre-computing sine tables, cryptographical lookup maps, or string hashes during compiling.
Self-Documenting Types: Creating physical representations in code using UDL suffixes (e.g. `_seconds`, `_px`).
Zero-Cost Maths: Computing factorials or complex algorithm parameters prior to deployment.
Common Mistakes
Confusing const with constexpr and using it in static array limits.
Calling non-constexpr processes inside a constexpr context.
Assuming constinit generates variables that are immutable.