首页 > 解决方案 > consteval 函数返回具有非平凡 constexpr 析构函数的对象

问题描述

如果一切顺利, C++20 将拥有新的consteval关键字和constexpr 析构函数。遗憾的是,我所知道的编译器目前没有实现consteval。以下代码有效吗?

struct A {
  constexpr ~A() {}
};

consteval A f() {
    return A{};
}

void test() {
    A a;
    a = f(); // <-- here
}

问题来自我标记的行——需要调用临时A返回的析构函数。f但它应该在完整表达式的末尾调用。所以在即时评价之外。

我没有从constevalconstexpr 析构函数论文中找到任何明确禁止这样做的引用,但我看不出它怎么可能是正确的。

以下代码在 C++20 中有效吗?这段代码应该发生什么?


笔记:

consteval 论文中,给出了这个例子。这里 consteval 函数在常量上下文之外被调用。

consteval int sqr(int n) {
  return n*n;
}
constexpr int r = sqr(100);  // Okay.
int x = 100;
int r2 = sqr(x);  // Error: Call does not produce a constant.

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

解决方案


我认为这段代码很好。

的突出方面consteval[expr.const]/12

如果表达式或转换可能被评估并且其最内部的非块范围是立即函数的函数参数范围,则表达式或转换位于立即函数上下文中。如果表达式或转换是立即函数的显式或隐式调用并且不在立即函数上下文中,则它是立即调用。立即调用应为常量表达式。

void test() {
    A a;
    a = f(); // <-- here
}

f()立即调用(它是对不在立即函数上下文中的立即函数的显式调用)。所以要求是f()必须是一个常量表达式。

注意: just f(), not a = f();,这里的赋值运算符不要求是常量表达式。

调用的一切都f()很好。的所有A特殊成员函数都可以在恒定评估时间内调用。的结果f()是常量表达式([expr.const]/10)的允许结果,同样因为它也不会触发那里的任何限制(A没有指针或引用成员,所以它们都没有引用没有静态的对象存储时间)。

最终,不断评估的问题归结为检查所有限制列表并查看是否有任何问题。我认为我们没有违反任何规则,所以这应该没问题。


推荐阅读