c++ - constexpr 构造函数无法满足要求,但仍然是 constexpr。为什么?
问题描述
该标准说明了dcl.constexpr/6中的模板 constexpr 函数/构造函数:
如果 constexpr 函数模板或类模板的成员函数的实例化模板特化不能满足 constexpr 函数或 constexpr 构造函数的要求,则该特化仍然是 constexpr 函数或 constexpr 构造函数,即使调用此类函数不能出现在常量表达式中。如果模板的特殊化在被视为非模板函数或构造函数时满足对 constexpr 函数或 constexpr 构造函数的要求,则该模板是格式错误的,不需要诊断。
有趣的部分是:
未能满足 ... constexpr 构造函数的要求,该特化仍然是 ... constexpr 构造函数
因此,即使构造函数被标记为constexpr
,它也可能不会在常量表达式中使用。
为什么会有这条规则?constexpr
当功能不满足要求时,为什么不删除?
当前的行为在两个方面不好:
- 非 constexpr-ness 不会在最近的可能位置捕获,而是在使用它的实际 constexpr 表达式中捕获。所以我们必须找到有问题的部分,
constexpr
默默地删除。 - 旨在静态初始化的对象(因为它具有
constexpr
构造函数)将被动态初始化而没有任何错误/警告(因为构造函数不是“真正的” constexpr)。
这条规则是否有一些优点,平衡了它的缺点?
解决方案
此规则允许您编写模板化的构造函数/函数并将其标记为constexpr
即使它并不总是constexpr
(至少有时)。
例如,std::pair
有constexpr
构造函数,但它当然可以在常量表达式之外使用。
这是非常明智的,因为否则您将不得不复制所有这些功能(一次有constexpr
一次没有),即使代码完全相同。让我们甚至不考虑歧义。
由于通常不可能证明模板永远无法满足constexpr
,因此不需要对其进行诊断(但它的格式不正确,因此如果编译器可以针对给定的情况证明这一点,他们可能会向您抱怨)。
你是正确的,如果你想指定“这个函数只能在常量表达式中使用”,这不是很有用,但这不是这个措辞的目的。
编辑:澄清一下,constexpr
对于函数仅意味着“在常量表达式内进行评估的合法性” (此处更精确的措辞),而不是 “只能在编译时评估”。相反,constexpr
变量必须用常量表达式初始化。
另一个编辑:感谢@JackAidley,我们有确切的措辞要讨论!
如果 constexpr 函数模板的实例化模板特化不能满足 constexpr 函数的要求,
constexpr
则忽略说明符并且特化不是 constexpr 函数。
这样做的问题是“至少有一组参数可以对其进行常数评估”是“对 constexpr 函数的要求”的一部分。因此,编译器无法实现此子句,因为(通常)无法证明给定函数(或函数模板实例化)是否存在这样的集合。您要么必须进一步混淆此要求,要么放弃此方面。委员会似乎选择了后者。
推荐阅读
- lua - 客户端和服务器脚本问题 roblox studio
- javascript - 如何使用 jQuery 获取数据表行的内容?
- vue.js - 使用 Bootstrap Vuejs 将 row.item.attribute 值传递给模式
- azure - 在自定义数据库表中存储和显示调试信息,同时使用直线运行 botcomposer 机器人
- docker - Traefik Stack Deploy/Service 创建重复任务
- c - 从键盘读取字符串时出现意外输出
- java - Java:如何解决读写器问题?
- arduino - 如何在 LCD(16,2) 中使用移位寄存器
- android - 华为移动服务(HMS)异常:云端使用ML kit Real-Time Translation时Token无效或过期?
- c# - 无法将类型 db.entities1 隐式转换为 system.collection.generic.list
发布 WebAPI 时