c++ - 带有条件的 constexpr 类成员函数内的非 constexpr 变体成员调用编译 - 为什么?
问题描述
#include <variant>
struct S {
constexpr auto f() -> void {
// deleting the next line creates an error
if(std::holds_alternative<int>(m_var))
m_var.emplace<double>(5.0);
}
std::variant<int, double> m_var;
};
int main() {
return 0;
}
std::variant
有一个非constexpr
成员函数emplace()
。一般来说,你不能在constexpr
函数中使用它。但是,如果您用std::holds_alternative()
在该类型上使用的条件包围该调用,则可以。还有其他 constexpr 函数,只要它们是该类中的成员函数。
我很难理解发生了什么。我的第一反应是说这是一个错误。这个条件不可能比没有条件更 constexpr。但也许这还为时过早。任何人都可以对此有所了解吗?为什么emplace()
不是 constexpr 而是(相等类型)赋值?
编辑:也许扩展一下:一个猜测是所涉及的变体的构造函数和析构函数可能是非 constexpr ,这就是为什么emplace
etc 不是。但有趣的是,即使您明确滥用非 constexpr 构造函数,您也可以使用这样的条件将函数编译为 constexpr。这使该论点无效。
神箭:这里。
解决方案
您实际上不需要深入研究std::variant
即可对此进行推理。这主要是关于常量表达式的工作原理。constexpr
函数必须以允许在常量表达式中求值的方式定义。对于某些参数,我们是否遇到不能出现在常量表达式中的东西并不重要,只要对于其他参数,我们获得一个有效的常量表达式。标准中明确提到了这一点,并举了一个例子
[dcl.constexpr]
5对于既不是默认也不是模板的 constexpr 函数或 constexpr 构造函数,如果不存在参数值,则函数或构造函数的调用可以是核心常量表达式的求值子表达式,或者,对于构造函数,是常量初始值设定项对于某些对象([basic.start.static]),程序格式错误,不需要诊断。[ 例子:
constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required struct B { constexpr B(int x) : i(0) { } // x is unused int i; }; int global; struct D : B { constexpr D() : B(global) { } // ill-formed, no diagnostic required // lvalue-to-rvalue conversion on non-constant global };
—结束示例]
看看f(bool)
一个有效的constexpr
功能如何?即使throw
表达式可能不会在常量表达式中求值,它仍然可以出现在constexpr
函数中。只要不断的评估没有达到它就没有问题。
如果没有constexpr
可以在常量表达式中使用函数的参数集,则程序格式错误。这种格式错误的程序不需要诊断,因为仅从函数定义中检查这种情况通常是难以处理的。然而,它是无效的 C++,即使编译器没有引发错误。但在某些情况下,它可以被检查,因此编译器可能不得不提出诊断。
您f
没有条件属于此类不正确的构造。不管怎么f
调用,它的执行都会导致调用emplace
,不能出现在常量表达式中。但它很容易检测到,所以你的编译器会告诉你这是一个问题。
您的第二个版本,带有条件,不再emplace
无条件调用。现在是有条件的。条件本身依赖于一个constexpr
函数,所以它不会立即不正确。一切都取决于函数的参数(this
包括)。所以它不会立即引发错误。
推荐阅读
- typescript - 为什么启用了 strictFunctionTypes 选项的 TypeScript 在我传递超过 8 个 rxjs 运算符时会引发类型分配错误?
- python - 从 DataFrame 中删除仅在一列中包含单个唯一值的组
- javascript - 如何在摩卡测试中使用乘法异步函数
- sql - 使用 CTE 获取数据但使用不起作用的东西
- python - 如果答案在列表中正确或不正确,如何打印然后添加到分数
- python - 基于日期时间戳和来自 json 输入文件的整数值生成相同的 uuid
- regex - 为什么正则表达式模式 \r\n(?=$) 在 powershell 中不起作用?
- python - 有没有办法用 ARIMA 模型获得密度预测?
- php - 如何获取帖子并为 Wordpress 添加帖子导航链接?
- javascript - nodejs Twit 发布一个随机的 youtube 链接