Introduction
While working on a personal project, I learned about constexpr. I understood the difference between const and constexpr. However, I wondered why constexpr is necessary when const seems sufficient. I want to share what I found in this article.
const
A keyword that promises the compiler that a value cannot be changed.
Once initialized, the value cannot be modified.
const int MAX_USERS = 100;
MAX_USERS = 200; // Compilation error!
Characteristics
- The initialization value can be known at compile time or at runtime.
int A;
std::cin >> A;
const int B = A; // Valid
// Constant B is determined at runtime, but cannot be changed afterwards.
// The value doesn't need to be known at compile time, but once set, it cannot be changed.
- It becomes more powerful when used with references and pointers.
const int* ptr1; // Cannot change the pointed value
int* const ptr2; // Cannot change the pointer itself
const int* const ptr3; // Cannot change both
- When
constis added to a class member function, the function promises not to change the object's state.
class User {
private:
std::string name;
int age;
public:
// Does not modify member variables
std::string getName() const {
return name;
// age = 30; // Error occurs
}
void setAge(int newAge) {
age = newAge; // Valid
}
};
Limitations
- If a member variable is declared as
mutable, it can be modified even inconstmember functions. -
constcan be forcibly removed usingconst_cast.
constexpr
constexpr is short for "constant expression".
Unlike const, it is a keyword that guarantees the compiler that the value is determined at compile time.
It was first introduced in C++11, and most restrictions have been lifted through version updates.
constexpr int func(int n) {
return n * n;
}
constexpr int A = 1; // Initialized to 1 at compile time
constexpr int B = func(2); // Calculated to 4 at compile time
constexpr int C = func(B); // Calculated to 16 at compile time
The critical difference from const is as follows:
int func() {
int value;
std::cin >> value;
return value;
}
const int a = func(); // Valid -> because it's determined at runtime
constexpr int b = func(); // Error occurs
Reasons to Use
- Performance is improved as complex calculations can be completed at compile time through compile-time computation.
- In C++, array sizes and template arguments must be compile-time constants.
- Incorrect calculations can be caught before execution.
- The compiler can perform more verification.
// 1. Performance improvement
constexpr int factorial(int n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
constexpr int result = factorial(10); // Zero calculation cost at runtime
// 2. Array size
constexpr int SIZE = 100;
int buffer[SIZE]; // OK
const int size = getSize();
int arr[size]; // Error in most cases
// 3. Compile-time verification
constexpr int divide(int a, int b) {
return b == 0 ? throw "error" : a / b;
}
constexpr int x = divide(10, 0); // Compilation error occurs
When to Use const vs constexpr?
When to use const
- Use when the value can be known at runtime, such as user input, configuration values read from files.
- Use
constto express the intention not to modify arguments passed to a function. - Member functions that do not change the object's state should be declared as
const.
When to use constexpr
- C++ array sizes must be compile-time constants.
- Template parameters must be determined at compile time.
- Use when you want to pre-calculate complex computations.
- Use in
switchstatementcaselabels,static_assert, etc.
| Situation | const | constexpr |
|---|---|---|
| User input value | O | X |
| Array size | △ | O |
| Template argument | X | O |
| Function parameter | O | X |
| Compile-time calculation | △ | O |
Summary
const is a promise of immutability, and constexpr is a guarantee of compile-time calculation.
const can accept runtime values, but constexpr is determined only at compile time.
Top comments (0)