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

经常想到的一个例子是:

sizeofexpression式,它不计算expression式,但是通过静态types来确定大小。 例如 :

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

这是我思考的极限,所以如果还有其他未被评估的情境,那么它们是什么?

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

在某些情况下,出现未评估的操作数 (5.2.8,5.3.3,5.3.7,7.1.6.2)。 未评估的操作数未被评估。 一个未被评估的操作数被认为是一个完整的expression式。

我们来仔细看看这些。

我将在我的例子中使用下面的声明。 声明的函数从来没有在任何地方定义过,所以如果一个调用它们出现在一个评估的上下文中,程序是不合格的,我们将得到一个链接时间错误。 然而,在没有评估的情况下调用它们是很好的。

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

typeid

§5.2.8 [expr.typeid]¶3:

typeid应用于除多态类types的glvalue以外的expression式时 ,结果引用表示expression式的静态types的std::type_info对象。 左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)的转换不适用于expression式。 如果expression式的types是一个类的types,那么该类将被完全定义。 expression式是一个未评估的操作数(第5章)。

注意多态类(一个至less有一个virtual成员的类)的强调exception。

所以,这没关系

 typeid( foo() ) 

并为此产生一个std::type_info对象

 typeid( widget::get_instance() ) 

不是,可能会产生链接时间错误。 它必须评估操作数,因为dynamictypes是通过在运行时查找vptr来确定的。

我发现这样一个事实令人困惑:操作数的静态types是否是多态的,会以如此戏剧性而又微妙的方式改变操作符的语义。</ rant>

sizeof

§5.3.3 [expr.sizeof]¶1:

sizeof运算符产生其操作数的对象表示forms中的字节数。 操作数是一个expression式,它是一个未被评估的操作数(条款5) ,或者是一个带括号的types标识符sizeof运算符不能被应用到一个具有函数或不完整types的expression式,在枚举types的基本types在其所有枚举符被声明之前是不固定的,也可能被应用到这种types的括号中,或者指定一个glvalue位字段。

下列

 sizeof( foo() ) 

是完全正确的,相当于sizeof(int)

 sizeof( widget::get_instance() ) 

也是允许的。 但是请注意,它相当于sizeof(widget) ,因此对于多态returntypes可能不是很有用。

noexcept

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

noexcept操作符确定操作数(未评估的操作数(第5章))的评估是否可以抛出exception(15.1)。

expression方式

 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; 

声明一个inttypes的variablesn并用值42初始化它。

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

声明一个不带参数的函数baz ,并return一个sa widget&

这就是所有(就像C ++ 14一样)。

标准术语是一个未评估的操作数 ,您可以在[expr]

在某些情况下,出现未评估的操作数(5.2.8,5.3.3,5.3.7,7.1.6.2)。 未评估的操作数未被评估。 一个未被评估的操作数被认为是一个完整的expression式。 [注意:在一个未评估的操作数中,非静态类成员可以被命名为(5.1),而对象或函数的命名本身并不要求提供定义(3.2)。 – 注意]

  • 5.2.8涵盖了typeid
  • 5.3.3涵盖了sizeof
  • 5.3.7涵盖noexcept
  • 7.1.6.2包含简单的types说明符,如autodecltype和PODtypes,如intchardouble