首页 > 解决方案 > constexpr 构造函数无法满足要求,但仍然是 constexpr。为什么?

问题描述

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

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

有趣的部分是:

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

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

为什么会有这条规则?constexpr当功能不满足要求时,为什么不删除?

当前的行为在两个方面不好:

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

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

解决方案


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

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

这是非常明智的,因为否则您将不得不复制所有这些功能(一次有constexpr一次没有),即使代码完全相同。让我们甚至不考虑歧义。

由于通常不可能证明模板永远无法满足constexpr,因此不需要对其进行诊断(但它的格式不正确,因此如果编译器可以针对给定的情况证明这一点,他们可能会向您抱怨)。

你是正确的,如果你想指定“这个函数只能在常量表达式中使用”,这不是很有用,但这不是这个措辞的目的。

编辑:澄清一下,constexpr 对于函数仅意味着“在常量表达式内进行评估的合法性” (此处更精确的措辞),而不是 “只能在编译时评估”。相反,constexpr变量必须用常量表达式初始化。


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

如果 constexpr 函数模板的实例化模板特化不能满足 constexpr 函数的要求,constexpr则忽略说明符并且特化不是 constexpr 函数。

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


推荐阅读