Constexpr构造函数无法满足要求,但仍然是constexpr.为什么?

gez*_*eza 7 c++ language-lawyer c++17

该标准说明了dcl.constexpr/6中的模板constexpr函数/构造函数:

如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足constexpr函数或constexpr构造函数的要求,那么该特化仍然是constexpr函数或constexpr构造函数,即使调用这样的函数不能出现在常量表达式中.如果模板的特化不满足constexpr函数或constexpr构造函数在被视为非模板函数或构造函数时的要求,则模板格式错误,无需诊断.

有趣的是:

无法满足... constexpr构造函数的要求,该特化仍然是... constexpr构造函数

因此,即使构造函数被标记constexpr,也不能在常量表达式中使用它.

为什么存在这个规则?constexpr当功能不满足要求时,为什么不删除?

目前的行为在两个方面很糟糕:

  • 非constexpr-ness不是在最近的可能位置捕获,而是在实际的constexpr表达式中使用它.所以我们必须找到有问题的部分,在那里constexpr默默地删除.
  • 一个对象,打算静态初始化(因为它有一个constexpr构造函数),将动态初始化,没有任何错误/警告(因为构造函数不是"真正"constexpr).

这条规则是否有一些优点,这可以平衡它的缺点?

Max*_*hof 5

此规则允许您编写模板化构造函数/函数,并将其标记为constexpr即使并非总是constexpr(至少有时).

例如,std::pairconstexpr构造函数,但它当然可以在常量表达式之外使用.

这是非常明智的,因为否则你将不得不复制所有这些函数(一次使用constexpr,一次不使用),即使代码完全相同.我们甚至不考虑歧义.

由于通常不可能证明模板不能满足constexpr,因此不需要诊断(但它是不正确的,因此如果他们能够针对给定的情况证明这一点,编译器可以向您抱怨).

你是正确的,如果你想指定"这个函数只能用于常量表达式" 这不是很有用,但这不是这个措辞的目标.

编辑:为了澄清,constexpr 对于函数而言,仅意味着"在常量表达式内进行合法评估"(此处更准确的措辞),而不是 "只能在编译时进行评估".相反,constexpr必须使用常量表达式初始化变量.


另一个编辑:感谢@JackAidley,我们有准确的措辞要讨论!

如果constexpr函数模板的实例化模板特化将无法满足constexpr函数的要求,constexpr则忽略指定符并且特化不是constexpr函数.

这个问题是"至少有一组参数可以对函数进行常量评估"是"constexpr函数的要求"的一部分.因此,编译器无法实现此子句,因为不可能(通常)证明给定函数(或函数模板实例化)是否存在这样的集合.你要么必须进一步混淆这个要求,要么放弃这个方面.委员会似乎选择了后者.

  • 我想你误解了'constexpr`对函数的意义.`constexpr`函数_can_在编译时被评估(对于一些参数集).对于每一种选择,他们都不会被保证.如果需要在编译时初始化值,请将值标记为"constexpr"(这将强制执行此问题).仅标记函数只是使函数在常量表达式中使用是合法的,它不需要每次调用都在编译时. (3认同)