问题
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")
回答1:
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 aconstexpr
function template or member function of a class template would fail to satisfy the requirements for aconstexpr
function orconstexpr
constructor, that specialization is still aconstexpr
function orconstexpr
constructor, 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 aconstexpr
function orconstexpr
constructor 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.
来源:https://stackoverflow.com/questions/53630837/is-this-a-bug-constexpr-constructor-silently-becomes-non-constexpr