为何此处默认构造函数非constexpr?Clang与GCC编译差异谁正确?
问题解答:GCC的行为符合C++标准
先贴出你提供的代码供参考:
#include <type_traits> template<typename T> struct MyType { constexpr MyType () = default; //constexpr MyType () {} constexpr bool is_int () const { return std::is_same_v<T, int>; } }; constexpr auto foo () { MyType<int> retval; //MyType<int> retval {}; return retval; } int main () { static_assert (foo ().is_int ()); }
核心结论
首先明确:GCC拒绝编译这段代码是符合C++标准的,Clang的接受属于非标准的宽松实现行为。
原因拆解
问题出在constexpr函数里的对象初始化方式,以及MyType默认构造函数的定义:
- 你用
constexpr MyType() = default;声明了一个平凡(trivial)的constexpr构造函数——因为类没有非静态数据成员,这个构造函数实际上不会执行任何初始化操作,只是“空转”。 - 在
constexpr函数中,变量的初始化必须是合法的常量表达式。标准要求,constexpr上下文中的对象必须有明确的、可被编译器求值的常量状态;而平凡constexpr构造函数的默认初始化(MyType<int> retval;),编译器无法确认这个对象的状态满足常量表达式的要求,因此GCC会拒绝编译。
为什么取消任意一行注释就能编译?
两种修改都补上了“常量表达式初始化”的合规性:
- 改成用户提供的构造函数
constexpr MyType() {}:
此时构造函数不再是平凡的——哪怕函数体为空,它也是用户显式定义的constexpr构造函数。编译器会认定这个构造函数的调用是合法的常量表达式,满足constexpr上下文的要求。 - 改成值初始化
MyType<int> retval {};:
值初始化的语法会强制触发构造函数调用,哪怕构造函数是平凡的,编译器也会将这个初始化过程视为符合constexpr要求的操作,从而通过编译。
内容的提问来源于stack exchange,提问作者levzettelin
相关产品推荐
相关产品推荐

