Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A constexpr member variable is a class-level data member whose value is strictly evaluated and fixed at compile-time. In C++, a constexpr member variable must be declared as static, meaning it belongs to the class itself rather than any specific object instance, and it is implicitly const. C++ prohibits non-static constexpr member variables because a constexpr variable declaration must define a single, globally fixed value associated with the declaration itself. Non-static members, by contrast, represent per-instance state that is initialized by constructors. To achieve compile-time initialization for per-instance data, the correct language mechanism is to declare a standard const member and initialize it via a constexpr constructor.

Syntax and Initialization Rules

  1. In-Class Initialization: The variable must be initialized at the point of declaration inside the class definition.
  2. Constant Expression: The initializer must be a valid constant expression.
  3. Literal Type: The type of the variable must be a literal type. This includes scalar types, references, or class types that possess a constexpr constructor and a constexpr destructor (as of C++20, literal types are no longer required to have a strictly trivial destructor).
class Configuration {
public:
    // Valid: static, literal type, initialized with a constant expression
    static constexpr int MaxConnections = 256;
    static constexpr double TimeoutSeconds = 30.5;

    // Invalid: constexpr members must be static
    // constexpr int InstanceId = 1; 

    // Invalid: initializer is not a constant expression
    // static constexpr int RandomSeed = getRandomNumber(); 
};

Linkage and the One Definition Rule (ODR)

The behavior of static constexpr member variables regarding the One Definition Rule (ODR) changed significantly in C++17.

C++17 and Later (Implicitly Inline)

As of C++17, a static constexpr member variable is implicitly inline. The in-class declaration serves as the complete definition. Even if the variable is ODR-used (e.g., its address is taken or it is bound to a reference), no out-of-line definition is required.
class Server {
public:
    static constexpr int Port = 8080; // Declaration and definition (C++17+)
};

// Valid in C++17 without any out-of-line definition
const int* portPtr = &Server::Port; 

Pre-C++17 (C++11 / C++14)

In older standards, the in-class declaration is only a declaration. If the variable is strictly used as an rvalue (e.g., passing it by value), the compiler substitutes the value directly. However, if the variable is ODR-used, a single out-of-line definition must be provided in exactly one translation unit (.cpp file), without repeating the initializer.
// Header file (.h)
class Server {
public:
    static constexpr int Port = 8080; // Declaration
};

// Source file (.cpp) - Required pre-C++17 if ODR-used
constexpr int Server::Port; // Definition (no initializer allowed here)

Complex Literal Types

A static constexpr member is not limited to primitive types. It can be a user-defined class type, provided that the class meets the requirements of a literal type.
struct Point {
    int x;
    int y;
    
    constexpr Point(int x, int y) : x(x), y(y) {}
    constexpr ~Point() = default; // Satisfies C++20 literal type requirements
};

class Grid {
public:
    // Valid: Point is a literal type with a constexpr constructor
    static constexpr Point Origin{0, 0};
};
Master C++ with Deep Grasping Methodology!Learn More