幸运的是,该标准有一个方便的列表(§ 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:
When typeid
应用于多态类类型的左值以外的表达式,结果指的是std::type_info
表示表达式的静态类型的对象。左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 转换不适用于表达式。如果表达式的类型是类类型,则该类应是完全定义的。该表达式是未计算的操作数
(第 5 条)。
请注意多态类的强调例外(aclass
至少有一个virtual
成员)。
因此,这是可以的
typeid( foo() )
并产生一个std::type_info
对象为int
而这
typeid( widget::get_instance() )
不是并且可能会产生链接时错误。它必须评估操作数,因为动态类型是通过查找来确定的vptr
在运行时。
我发现很令人困惑的是,操作数的静态类型是否是多态的这一事实以如此戏剧性但微妙的方式改变了运算符的语义。
sizeof
§ 5.3.3 [expr.sizeof] ¶ 1:
The sizeof
运算符产生其操作数的对象表示形式中的字节数。操作数是一个表达式,它是一个未计算的操作数(第 5 条),或带括号的type-id. The sizeof
运算符不得应用于具有函数或不完整类型的表达式、在声明其所有枚举器之前其基础类型未固定的枚举类型、此类类型的括号名称或指定位的泛左值。场地。
下列
sizeof( foo() )
完全没问题,相当于sizeof(int)
.
sizeof( widget::get_instance() )
被允许。但请注意,它相当于sizeof(widget)
因此对于多态可能不是很有用return
type.
noexcept
§ 5.3.7 [expr.unary.noexcept] ¶ 1:
The 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;
声明一个变量n
类型的int
并用值 42 对其进行初始化。
auto baz() -> decltype( widget::get_instance() );
声明一个函数baz
不需要任何参数并且return
s a widget&
.
这就是全部(从 C++14 开始)。