[英]Why can I call a non-constexpr function inside a constexpr function?
[英]Non-constexpr variant member call compiling inside constexpr class member function with condition - why?
#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
等不是。 但有趣的是,即使您明确滥用非 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
函数,因此它不会立即constexpr
。 一切都将取决于函数的自变量( this
包括)。 所以它不会立即引发错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.