constexpr函数是否允许返回非字面量类型?
问题复现代码
struct Outer { explicit constexpr Outer(int ii) : n(ii) {} explicit constexpr Outer(double dd) : n(dd) {} explicit constexpr Outer(double*) : Outer(3.1415926) {} explicit constexpr Outer(int*): Outer(42) {} template <typename R> static constexpr Outer meow(R* r = nullptr) { return Outer(r); } int as_i() const { return n.i; } double as_d() const { return n.d; } union Inner { int i; double d; constexpr Inner(int ii) : i(ii) {} constexpr Inner(double dd) : d(dd) {} ~Inner () {}; // 非平凡析构函数 }; Inner n; }; //#include <type_traits> //static_assert(std::is_literal_type_v<Outer>); // GCC和Clang均会判定该断言失败 int main(int argc, char**) { auto const o = Outer::meow(&argc); return o.as_i(); }
编译行为差异
- 上述代码可被GCC 12.1正常编译,但会被Clang 14.0.0拒绝。
- 在线编译验证地址:Godbolt在线验证
Clang编译报错输出
从C++语法规则判定,Clang的行为是正确的,对应报错内容如下:
<source>:12:11: error: constexpr function's return type 'Outer' is not a literal type Outer meow(R* r = nullptr) { return Outer(r); } ^ <source>:28:11: note: 'Outer' is not literal because it has data member 'n' of non-literal type 'Outer::Inner' Inner n; ^ <source>:36:24: error: no matching function for call to 'meow' auto const o = Outer::meow(&argc); ^~~~~~~~~~~ <source>:12:11: note: candidate template ignored: substitution failure [with R = int] Outer meow(R* r = nullptr) { return Outer(r); } ^
核心疑问
即便变量o仅被const修饰、并未声明为constexpr,上述写法难道不应当报错吗?meow作为constexpr函数返回非字面量类型的行为本身就不符合语法规则。
补充测试现象
如果将o声明为constexpr变量,GCC也会抛出错误,提示Outer类型存在非平凡析构函数。
内容的提问来源于stack exchange,提问作者Bulletmagnet
相关产品推荐
相关产品推荐

