在'requires expression'看来,未计算的操作数是什么?

What is an unevaluated operand in the way a 'requires expression' sees it?

本文关键字:操作数 计算 是什么 看来 requires expression      更新时间:2024-09-23

标准[expr.prim.req.general]中的注释2指出:

出现在需求体中的表达式是未赋值的操作数。

简单地说,未求值的操作数是未求值的操作数。

考虑以下代码:

#include <iostream>
int fun(int) { return 5; }
template<typename R>
struct T { static R x; };
int main() {
std::cout << fun(T<int>::x)  << std::endl;                    // Line A
std::cout << requires { fun(T<int &&>::x); } << std::endl;    // Line B
//std::cout << requires { fun(T<int &&&>::x); } << std::endl;   // Error: Line C
}

毫无疑问,行A与预期的类型相匹配,并且编译良好。

行B与预期类型不匹配(-l和-r值不匹配(,但编译良好。

按照同样的推理,C行虽然包含一个明显的错误,但应该编译,因为操作数不应该被求值。不用说,我故意在这里创建一个语法错误的语句。Clang11和gcc10.2正确识别引用到引用错误。但是,在我的理解中,编译器正在进行模板推导,而语句应该是未求值的。

我的问题是:为什么fun(T<int &&&>::x);在我的代码中没有被赋值?相反,它正在被评估和模板推导。

最接近的答案是:这里和这里——但它们都是"未定义的行为"。我无法在代码的上下文中解释它们。我目前的猜测是,模板推导不属于未赋值操作数的类别。

表达式仍然需要语法正确(如中所述,符合标准所述的C++语法(,是否进行求值。根据语法,int&&&无效。(没有ref限定符ref限定符(

(您可以通过将左值传递给接收T&&的模板来获得这一点,但它将通过引用折叠而变为T&,但很明显,它是对引用的右值引用,而不是相反的方式——int&&&是模糊和无意义的(

未赋值的操作数通常是一个用于推断类型信息的表达式,而不是用于其副作用(而丢弃的值表达式仅用于其副效果(。未赋值操作数的其他示例:

T x;
auto typeInfo = typeid(x); // x is unevaluated
auto x_size = sizeof(x); // x is unevaluated

在上面的例子中,似乎很明显,x并没有真正做到,因为我们只是命名一个变量,但考虑到typeidsizeof的参数可以是任何表达式!表达式不会有任何副作用,因为它是未赋值;在这些情况下,我们只关心结果表达式的类型

需要表达式的情况下,需求体(大括号之间的位(需要

表达式对于所有编译器来说,您本可以编写requires{abra;!?...-cadabra}而不是requires{fun(T<int &&&>::x);},但它们同样无效。