C++ 这是虫子吗?Constexpr构造函数以静默方式变为非Constexpr

C++ 这是虫子吗?Constexpr构造函数以静默方式变为非Constexpr,c++,language-lawyer,c++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() { } }; struct unconstexpr{ 非结构化x

请看以下代码:

struct NonConstexpr {
    NonConstexpr() { }
};

template <typename T>
struct Bar {
    NonConstexpr nonConstexpr;

    constexpr Bar() { }
};

struct Foo {
    Bar<void> bar;

    constexpr Foo() { }
};
struct unconstexpr{
非结构化xpr(){}
};
模板
结构条{
非stexpr非stexpr;
constexpr Bar(){}
};
结构Foo{
酒吧;
constexpr Foo(){}
};
Foo
有一个成员,
Foo::bar::nonConstexpr
,它有一个非constexpr构造函数。因此,我的期望是,这不应该编译。但它是用gcc、clang和msvc编译的。这是一个编译器错误,还是某些规则允许编译此代码

如果我直接在
Foo
中添加一个
noncostexpr
成员,代码就不会再编译了

(我遇到了这个问题,因为我期望对全局
Foo
对象进行静态初始化,但它得到了动态初始化,并导致了一个问题,因为“静态初始化顺序失败”)

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

允许进行编译的规则是:

10.1.5 constexpr规范[dcl.constexpr]


6.如果
constepr
函数模板或类模板的成员函数的实例化模板专门化不能满足
constepr
函数或
constepr
构造函数的要求,则该专门化仍然是
constepr
函数或
constepr
构造函数,即使对此类函数的调用不能出现在常量表达式中。如果模板的专门化不能满足
constepr
函数或
constepr
构造函数(当被视为非模板函数或构造函数时)的要求,则模板格式不正确,无需诊断

上述报价摘自CPP标准草案N4713



从引文中可能不清楚
Bar
的构造函数如何出现在
Foo
的构造函数中,因为
Foo
的构造函数是
constepr
。但正如注释中所指出的,
constexpr
与常量表达式不同
Foo
的构造函数不是一个表达式,更不用说是一个常量表达式。

允许它编译,但模板是格式错误的NDR。有趣,“即使对这样一个函数的调用不能出现在常量表达式中”。这是否意味着
Bar
的构造函数不能出现在
Foo
的构造函数中(
Foo
的构造函数是constexpr,而
Bar
的构造函数不是,所以它不能出现)?@geza-构造函数是constexpr,但不是常量表达式(根本不是表达式)。@geza:同意讲故事者的解释。构造器不是一个表达式。@StoryTeller:好的,谢谢,读了几遍这句话,再加上你的评论,现在我明白发生了什么。但是,现在我无法理解这背后的逻辑:“无法满足……constexpr构造函数的要求,这个专门化仍然是……constexpr构造函数”。什么?为什么?如果
Bar
不是模板,GCC不会编译此代码。或许,一个相关的问题: