The source of your confusion is probably thinking of "constexpr
" as "evaluated at compile time". While there is truth to this idea, it is imprecise. I would invite you to drop your current understanding of "constexpr
". Instead, start thinking of "constexpr
" as "allowed in constant expressions". The language provides a precise definition for "constant expression"; for present purposes, it might be enough to consider a constant expression to be an expression whose value can be computed by the compiler. (If the compiler computes that value, it would need to evaluate something at compile time. This leads to that imprecise notion of constexpr
.)
As you adjust your thinking to this new view, focus on the word "allowed". A person with a driver's license is allowed to drive a car but is not prohibited from riding a bicycle. A variable with the constexpr
specifier is allowed in constant expressions but is not prohibited from other expressions.
Warning: When dealing specifically with integer variables, the constexpr
specifier syntactically does not mean much more than const
. If an integer variable is both declared const
and initialized by a constant expression, then that variable is given the same privilege as a constexpr
—it is allowed in constant expressions. This is a limited special case that supports pre-C++11 code. To clearly express intent (semantics) in new code, any variable used in a constant expression should be constexpr
even if the language syntax allows it to be merely const
.
During compile time, test
doesn't exist yet, however, the above code compiles just fine.
Yes, code that has no syntax errors does tend to compile just fine. ;)
For variables, the only limitation imposed by constexpr
that is not imposed by const
is that the variable's initialization must be a constant expression (i.e. the value must be something the compiler can compute). You satisfied that by initializing id
to 5
rather than to some value determined at run time. Your use of id
after initialization is consistent with the use of a const int
, so that use is valid for a constexpr int
.
If test
doesn't exist yet then how can getId
exist during compile time?
I guess that depends on what you mean by "exist". In one sense, a function exists from the moment the compiler generates its object code. That code gets incorporated into the final executable. The object code does not need to be constructed during run time (only loaded from disk), so one could say the function started existing before the program was run. There are caveats, but the general idea is valid.
In a similar way, one could say that the class test
exists during compilation, but I suspect you meant that instantiations (objects) of test
don't exist yet.
If you had another meaning for "exist" in mind, then your claim that getId
exists during compile time is possibly false. (In particular, getId
is not executed during compilation.)
[From a comment:] What does it mean to say id
is evaluated at compile time?
Correction: id
can be evaluated at compile time. It can also be evaluated at run time. What actually happens depends on how id
is used. If you do not give the compiler a reason to evaluate id
, it does not have to.
[From a comment:] how can it evaluate id
during compile time if getId
(the parent) is only evaluated during run time.
The only place id
is used in your code is in a return
statement. The compiler is free to replace return id;
with return 5;
when it generates the object code for getId
. (Not a particularly interesting example, but technically an evaluation of id
at compile time. A more interesting example would use id
in a context that requires a constant expression.)