const / constexpr
The const qualifier in C++ marks variables, arguments, and member functions as immutable. Since C++11, constexpr allows declaring constants and functions whose values are determined at compile time. Using constexpr eliminates runtime overhead and enables the values to be used as template arguments and array sizes.
Syntax
// --- const ---
const int MAX_HP = 9000; // constant variable (may be initialized at runtime)
const double PI = 3.14159265;
// Passes argument without copy and prevents modification
void printName(const std::string& name);
// const member function: the function does not modify the object's state
class Pilot {
int syncRate;
public:
int getSyncRate() const { return syncRate; }
};
// --- constexpr ---
constexpr int MAX_ANGELS = 17; // compile-time constant
constexpr double G = 9.80665;
// constexpr function: evaluated at compile time when arguments are constant expressions
constexpr int square(int n) {
return n * n;
}
constexpr int area = square(5); // becomes 25 at compile time
int arr[square(3)]; // usable as array size (= arr[9])
// --- Difference from const ---
// const : can be a runtime constant (initializer need not be a constant expression)
// constexpr: must be a compile-time constant (initializer must be a constant expression)
int runtimeValue = 42;
const int c1 = runtimeValue; // OK (initialized at runtime)
// constexpr int c2 = runtimeValue; // error (not a constant expression)
Syntax Reference
| Syntax / Concept | Description |
|---|---|
| const variable | Declares an immutable variable. The initializer may be a runtime value or a function return value. |
| const argument (by reference) | Receiving as const T& passes without copying and prevents modification. A common idiom for efficiently passing large objects. |
| const member function | Adding const at the end of a member function signature makes it a read-only function callable on const objects or pointers. |
| constexpr variable | Declares a compile-time constant. Usable as template arguments, array sizes, and switch case labels. |
| constexpr function | Evaluated at compile time when arguments are constant expressions. Also callable at runtime with runtime values, in which case it behaves as a normal function. |
| constexpr constructor | Adding constexpr to a constructor allows the object itself to be a compile-time constant (C++11 and later). |
Sample Code
eva_const.cpp
#include <iostream>
#include <string>
// constexpr compile-time constants
constexpr int MAX_SYNC_RATE = 400;
constexpr int EVA_UNIT_COUNT = 3;
constexpr int ANGEL_COUNT = 17;
// constexpr function: determines awakening state at compile time
constexpr bool isAwakened(int syncRate) {
return syncRate >= 400;
}
constexpr int square(int n) {
return n * n;
}
// Struct with a constexpr constructor
struct EvaSpec {
int unitNumber;
int designSyncLimit;
constexpr EvaSpec(int unit, int limit)
: unitNumber(unit), designSyncLimit(limit) {}
constexpr bool isOverLimit(int syncRate) const {
return syncRate > designSyncLimit;
}
};
constexpr EvaSpec UNIT_01(1, 400);
constexpr EvaSpec UNIT_02(2, 400);
constexpr EvaSpec UNIT_00(0, 400);
// const reference argument: receives string without copying
void printPilot(const std::string& pilotName, int syncRate) {
std::cout << "Pilot: " << pilotName
<< " Sync rate: " << syncRate << "%" << std::endl;
if (isAwakened(syncRate)) {
std::cout << " *** AWAKENED ***" << std::endl;
}
}
// Class with const and non-const member functions
class Pilot {
std::string name;
int syncRate;
public:
Pilot(const std::string& name, int syncRate)
: name(name), syncRate(syncRate) {}
// const member functions: do not modify the object
std::string getName() const { return name; }
int getSyncRate() const { return syncRate; }
void showStatus() const {
std::cout << "Pilot: " << name
<< " Sync: " << syncRate << "%" << std::endl;
}
// non-const member function: modifies the object
void updateSyncRate(int newRate) {
syncRate = (newRate < MAX_SYNC_RATE) ? newRate : MAX_SYNC_RATE;
}
};
int main() {
std::cout << "=== Constants ===" << std::endl;
std::cout << "Max sync rate : " << MAX_SYNC_RATE << "%" << std::endl;
std::cout << "Eva unit count: " << EVA_UNIT_COUNT << std::endl;
std::cout << "Angel count : " << ANGEL_COUNT << std::endl << std::endl;
// constexpr function evaluated at compile time
constexpr int logBufferSize = square(16); // 256 at compile time
std::cout << "Log buffer size: " << logBufferSize << " bytes" << std::endl;
int runtimeSync = 400;
std::cout << "Awakened (runtime): " << (isAwakened(runtimeSync) ? "true" : "false")
<< std::endl << std::endl;
std::cout << "=== Unit specs ===" << std::endl;
std::cout << "Unit-01 design sync limit: " << UNIT_01.designSyncLimit << "%" << std::endl;
std::cout << "Unit-01 sync 410% exceeds limit: "
<< (UNIT_01.isOverLimit(410) ? "yes" : "no") << std::endl << std::endl;
std::cout << "=== Pilot sync rates ===" << std::endl;
const Pilot shinji("Ikari Shinji", 400); // const object
Pilot rei ("Ayanami Rei", 360);
Pilot asuka ("Asuka Langley", 300);
Pilot kaworu("Nagisa Kaworu", 999);
Pilot misato("Katsuragi Misato", 0);
shinji.showStatus(); // const member function callable on const object
// shinji.updateSyncRate(350); // compile error: non-const function on const object
rei.showStatus();
rei.updateSyncRate(375);
std::cout << " -> Updated sync: " << rei.getSyncRate() << "%" << std::endl;
asuka.showStatus();
kaworu.showStatus();
misato.showStatus();
std::cout << std::endl;
std::cout << "=== Awakening check ===" << std::endl;
printPilot(shinji.getName(), shinji.getSyncRate());
printPilot(kaworu.getName(), kaworu.getSyncRate());
printPilot(asuka.getName(), asuka.getSyncRate());
return 0;
}
g++ -std=c++14 eva_const.cpp -o eva_const ./eva_const === Constants === Max sync rate : 400% Eva unit count: 3 Angel count : 17 Log buffer size: 256 bytes Awakened (runtime): true === Unit specs === Unit-01 design sync limit: 400% Unit-01 sync 410% exceeds limit: yes === Pilot sync rates === Pilot: Ikari Shinji Sync: 400% Pilot: Ayanami Rei Sync: 360% -> Updated sync: 375% Pilot: Asuka Langley Sync: 300% Pilot: Nagisa Kaworu Sync: 400% Pilot: Katsuragi Misato Sync: 0% === Awakening check === Pilot: Ikari Shinji Sync rate: 400% *** AWAKENED *** Pilot: Nagisa Kaworu Sync rate: 400% *** AWAKENED *** Pilot: Asuka Langley Sync rate: 300%
Common Mistake 1: Initializing a constexpr variable with a runtime value
The initializer of a constexpr variable must be a constant expression. Using a runtime value causes a compile error.
// NG: runtime value cannot initialize constexpr int runtimeSync = 400; constexpr int limit = runtimeSync; // error: 'runtimeSync' is not a constant expression
OK: Use const for values determined at runtime.
// OK: const accepts runtime values int runtimeSync = 400; const int limit = runtimeSync; // OK
Common Mistake 2: Modifying a member variable inside a const member function
A const member function is read-only; attempting to modify a member variable inside one causes a compile error.
// NG: modifying a member variable in a const member function
class Pilot {
int syncRate;
public:
void boost() const {
syncRate += 10; // error: assignment of member in read-only object
}
};
OK: Do not mark a function const if it modifies member variables.
// OK: functions that modify state must not be const
class Pilot {
int syncRate;
public:
void boost() { // no const -> modification allowed
syncRate += 10;
}
int getSyncRate() const { return syncRate; } // read-only -> const
};
Overview
const is a qualifier that forbids modification of variables, arguments, and member functions. Receiving arguments as const T& avoids copying while preventing modification — a common idiom when passing strings and large objects to functions. A const at the end of a member function signature means "this method does not change the object's state" and allows the function to be called on const objects. constexpr (C++11 and later) guarantees that a value is determined at compile time, making it usable wherever an integer constant expression is required — template arguments, array sizes, and switch case labels. A constexpr function is evaluated at compile time when its arguments are constant expressions; it also works as a normal function when called with runtime values. The key difference from const is that a constexpr initializer must be a constant expression, otherwise the code does not compile. Since C++14, constexpr functions may contain multiple statements and local variables, enabling more complex compile-time computations.
If you find any errors or copyright issues, please contact us.