Look at this code:
struct NonConstexpr {
NonConstexpr() { }
};
template <typename T>
struct Bar {
NonConstexpr nonConstexpr;
constexpr Bar() { }
};
struct Foo {
Bar<void> bar;
constexpr Foo() { }
};
Foo has a member, Foo::bar::nonConstexpr, which has a non-constexpr constructor. So, my expectation is that this should not compile. But it compiles with gcc, clang and msvc. Is this a compiler bug, or some rule allows this code to compile?
If I add a NonConstexpr member into Foo directly, the code doesn't compile anymore.
(I got this problem, because I've expected static initialization for a global Foo object, but it got dynamically initialized, and it caused a problem, because of "static initialization order fiasco")
A constexpr function must accept and return only literal types. A constexpr function can be recursive. It can't be virtual. A constructor can't be defined as constexpr when the enclosing class has any virtual base classes.
constexpr stands for constant expression and is used to specify that a variable or function can be used in a constant expression, an expression that can be evaluated at compile time. The key point of constexpr is that it can be executed at compile time.
A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.
Using constexpr to Improve Security, Performance and Encapsulation in C++ constexpr is a new C++11 keyword that rids you of the need to create macros and hardcoded literals. It also guarantees, under certain conditions, that objects undergo static initialization.
Is this a compiler bug, or some rule allows this code to compile?
The rule that allows this to compile is:
10.1.5 The constexpr specifier [dcl.constexpr]
...
6. If the instantiated template specialization of aconstexprfunction template or member function of a class template would fail to satisfy the requirements for aconstexprfunction orconstexprconstructor, that specialization is still aconstexprfunction orconstexprconstructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for aconstexprfunction orconstexprconstructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required.
The above quote is taken from CPP standard draft N4713.
From the quote it may not be clear how Bar<void>'s constructor can appear in Foo's constructor as Foo's constructor is constexpr. But as noted in the comments, constexpr is not the same as constant expression. Foo's constructor is is not an expression, much less a constant expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With