什么是C++中未评估的上下文

What are unevaluated contexts in C++?

本文关键字:评估 上下文 C++ 什么      更新时间:2023-10-16

经常想到的一个例子是:

sizeof表达式,它不计算表达式,而是按静态类型确定大小。例如:

int func();
sizeof(func());

这是我的思维极限,所以如果还有其他未评估的上下文,那么它们是什么?

幸运的是,该标准有一个方便的列表(§ 5 [expr] ¶ 8):

在某些情况下,会出现未计算的操作数(5.2.8、5.3.3、5.3.7、7.1.6.2)。不计算未计算的操作数。未计算的操作数被视为完整表达式。

让我们详细看看这些。

我将在我的示例中使用以下声明。声明的函数永远不会在任何地方定义,因此如果对它们的调用出现在评估的上下文中,则程序格式不正确,我们将得到链接时间错误。但是,在未评估的上下文中调用它们是可以的。

int foo();  // never defined anywhere
struct widget
{
  virtual ~widget();
  static widget& get_instance();  // never defined anywhere
};

typeid

§ 5.2.8 [expr.typeid] ¶ 3:

typeid应用于多态类类型的 glvalue 以外的表达式时,结果将引用表示表达式的静态类型的std::type_info对象。左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 转换不应用于表达式。如果表达式的类型是类类型,则应完全定义该类。表达式是未计算的操作数 (第5条)。

请注意多态类(至少具有一个virtual成员的class)强调的异常。

因此,这没关系

typeid( foo() )

并生成一个std::type_info对象用于int

typeid( widget::get_instance() )

不是,并且可能会产生链接时错误。它必须计算操作数,因为动态类型是通过在运行时查找vptr来确定的。

我觉得很令人困惑的是,操作数的静态类型是否是多态的,这一事实以如此戏剧性但微妙的方式改变了运算符的语义

sizeof

§ 5.3.3 [扩展大小] ¶ 1:

sizeof运算符在其操作数的对象表示形式中生成字节数。操作数可以是表达式(即未计算的操作数(条款 5),也可以是带括号的类型 IDsizeof运算符不得应用于具有函数或不完整类型的表达式、其基础类型在声明其所有枚举器之前未固定的枚举类型、此类类型的括号名称或指定位字段的 glvalue。

以下

sizeof( foo() )

完全没问题,相当于sizeof(int).

sizeof( widget::get_instance() )

也是允许的。但请注意,它等效于sizeof(widget),因此在多态return类型上可能不是很有用。

noexcept

§ 5.3.7 [expr.unary.noexcept] ¶ 1:

noexcept运算符确定其操作数(即未计算的操作数(条款 5))的计算是否可以引发异常 (15.1)。

表达式

noexcept( foo() )

有效且计算结果为 false

这是一个更现实的例子,也是有效的。

void bar() noexcept(noexcept( widget::get_instance() ));

请注意,只有内部noexcept是运算符,而外部是说明符。

decltype

§ 7.1.6.2 [dcl.type.simple] ¶ 4.4:

decltype说明符的操作数是未计算的操作数(第 5 条)。

声明

decltype( foo() ) n = 42;

声明类型为 int 的变量n,并使用值 42 对其进行初始化。

auto baz() -> decltype( widget::get_instance() );

声明一个不带参数的函数bazreturn widget&

这就是全部(截至 C++14)。

标准项是一个未计算的操作数,你可以在 [expr] 中找到它。

在某些情况下,会出现未计算的操作数(5.2.8、5.3.3、5.3.7、7.1.6.2)。不计算未计算的操作数。未计算的操作数被视为完整表达式。[注意:在未求值的操作数中,可以命名非静态类成员(5.1),对象或函数的命名本身并不要求提供定义(3.2)。

  • 5.2.8 封面typeid
  • 5.3.3 封面sizeof
  • 5.3.7 封面noexcept
  • 7.1.6.2 涵盖了简单的类型说明符,如autodecltype和 POD 类型,如intchardouble等。