【问题标题】:Is this a bug? Constexpr constructor silently becomes non-constexpr这是一个错误吗? constexpr 构造函数静默变为非 constexpr
【发布时间】:2019-05-06 22:27:57
【问题描述】:

看看这段代码:

struct NonConstexpr {
    NonConstexpr() { }
};

template <typename T>
struct Bar {
    NonConstexpr nonConstexpr;

    constexpr Bar() { }
};

struct Foo {
    Bar<void> bar;

    constexpr Foo() { }
};

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

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

(我遇到了这个问题,因为我希望对全局 Foo 对象进行静态初始化,但它被动态初始化了,并且由于“静态初始化顺序惨败”而导致了问题)

【问题讨论】:

标签: c++ language-lawyer c++17


【解决方案1】:

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

允许编译的规则是:

10.1.5 constexpr 说明符 [dcl.constexpr]
...
6. 如果constexpr函数模板或类模板的成员函数的实例化模板特化不能满足constexpr函数或constexpr构造函数的要求,则该特化仍然是constexpr函数或@ 987654325@ 构造函数,即使对此类函数的调用不能出现在常量表达式中。如果模板的特殊化不能满足constexpr 函数或constexpr 构造函数的要求,当被视为非模板函数或构造函数时,则模板格式错误,不需要诊断。

以上引用摘自 CPP 标准草案 N4713。


从引用中可能不清楚Bar&lt;void&gt; 的构造函数如何出现在Foo 的构造函数中,因为Foo 的构造函数是constexpr。但正如 cmets 中所述,constexpr 与常量表达式不同。 Foo 的构造函数不是表达式,更不是常量表达式。

【讨论】:

  • 允许编译,但模板是格式错误的 NDR。很有趣。
  • “即使对此类函数的调用不能出现在常量表达式中”。这不是说Bar&lt;void&gt;的构造函数不能出现在Foo的构造函数中(Foo的构造函数是constexpr,而Bar&lt;void&gt;的不是,所以不能出现)?
  • @geza - 构造函数是 constexpr 但不是常量表达式(它根本不是表达式)。
  • @geza:同意 StoryTeller 的解释。构造函数不是表达式。
  • @StoryTeller:好的,谢谢,多次阅读此引文+您的评论,现在我明白发生了什么。但是,现在我无法理解这背后的逻辑:“未能满足 ... constexpr 构造函数的要求,该专业化仍然是 ... constexpr 构造函数”。什么?为什么?
猜你喜欢
  • 1970-01-01
  • 2016-07-29
  • 1970-01-01
  • 2013-12-24
  • 2016-07-23
  • 1970-01-01
  • 2018-10-04
  • 1970-01-01
  • 2020-10-08
相关资源
最近更新 更多