Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug? Constexpr constructor silently becomes non-constexpr

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")

like image 867
geza Avatar asked Dec 05 '18 11:12

geza


People also ask

Can a constructor be constexpr?

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.

What does constexpr mean?

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.

Is constexpr always evaluated 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.

Does constexpr improve performance?

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.


1 Answers

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 a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is still a constexpr function or constexpr 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 a constexpr function or constexpr 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.

like image 112
P.W Avatar answered Oct 18 '22 20:10

P.W