这是一个错误吗?Constexpr构造函数默默地变为非constexpr

gez*_*eza 17 c++ language-lawyer c++17

看看这段代码:

struct NonConstexpr {
    NonConstexpr() { }
};

template <typename T>
struct Bar {
    NonConstexpr nonConstexpr;

    constexpr Bar() { }
};

struct Foo {
    Bar<void> bar;

    constexpr Foo() { }
};
Run Code Online (Sandbox Code Playgroud)

Foo有一个成员,Foo::bar::nonConstexpr有一个非constexpr构造函数.所以,我的期望是这不应该编译.但它与gcc,clang和msvc编译.这是编译器错误,还是某些规则允许编译此代码?

如果我直接添加NonConstexpr成员Foo,代码将不再编译.

(我遇到了这个问题,因为我期望全局Foo对象的静态初始化,但它被动态初始化,并且由于"静态初始化命令惨败"而导致问题)

P.W*_*P.W 10

这是编译器错误,还是某些规则允许编译此代码?

允许这个编译的规则是:

10.1.5 constexpr指定程序[dcl.constexpr]
...
6.如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足constexpr函数或constexpr构造函数的要求,那么该特化仍然是一个constexpr函数或者constexpr构造函数,即使对这样的函数的调用不能出现在常量表达式中.如果在被视为非模板函数或构造函数时模板的特化不满足constexpr函数或constexpr构造函数的要求,则模板格式错误,无需诊断.

以上引用来自CPP标准草案N4713.


从引用中可能不清楚Bar<void>构造函数如何Foo作为构造函数出现在构造Foo函数中constexpr.但正如评论中所指出的,constexpr与常量表达式不同.Foo构造函数不是表达式,更不是常量表达式.