GCC编译类内static constexpr成员时默认初始化器报错求助
类内static constexpr聚合成员初始化报错的原因与解决办法
先看你给出的代码:
class A { public: struct B { unsigned int b0 = 10; unsigned int b1 = 11; }; A::B empty {}; const A::B emptyConst {}; static constexpr A::B emptyStaticConstexpr {}; };
用GCC 10.3.1以C17编译时,会报default member initializer for 'A::B::b0' required before the end of its enclosing class的错误,而把static constexpr A::B emptyStaticConstexpr {};移到类外就正常,核心原因是**C标准对类内static constexpr成员初始化的常量表达式要求**:
错误根源
static constexpr成员的初始化表达式必须是常量表达式,而在类A的定义还没结束(也就是末尾分号之前),嵌套结构体B里的默认成员初始化器(b0=10、b1=11)还不能被用于常量表达式求值。
- 普通成员
empty和const成员emptyConst的初始化不属于常量表达式求值范畴,编译器可以等类完全定义后再处理它们的初始化,所以不会触发错误; - 但static constexpr要求初始化过程必须在编译期完成,而类定义未结束时,编译器认为B的默认初始化器还未“生效”,无法用来生成合法的常量表达式。
不用重复数值的解决方案
方案1:类内声明,类外定义初始化
把static constexpr成员的初始化移到类外,此时类A已经完全定义,B的默认初始化器可以正常被常量表达式使用:
class A { public: struct B { unsigned int b0 = 10; unsigned int b1 = 11; }; A::B empty {}; const A::B emptyConst {}; static constexpr A::B emptyStaticConstexpr; // 仅类内声明 }; // 类外完成初始化,复用B的默认成员初始化器 constexpr A::B A::emptyStaticConstexpr {};
方案2:给B添加constexpr构造函数
用constexpr构造函数替代默认成员初始化器,这样在类内初始化static constexpr成员时,编译器可以直接调用构造函数生成常量表达式,不需要依赖未生效的默认初始化器:
class A { public: struct B { unsigned int b0; unsigned int b1; // 用constexpr构造函数初始化成员,避免重复数值 constexpr B() : b0(10), b1(11) {} }; A::B empty {}; const A::B emptyConst {}; // 现在类内初始化合法 static constexpr A::B emptyStaticConstexpr {}; };
内容的提问来源于stack exchange,提问作者ewrhuwaereww
相关产品推荐
相关产品推荐

