什么是C ++中未评估的上下文? [英] What are unevaluated contexts in C++?
问题描述
一个经常想到的例子是:
One example that frequently comes to mind is :
sizeof
表达式,它不评估表达式,但按静态类型确定大小。例如:
sizeof
expression, where it doesn't evaluates the expression but determines the size by static type. For example :
int func();
sizeof(func());
这是我的思维极限,因此,如果还有其他未评估的上下文,那么它们是什么? / p>
This is my limit of thinking, so if there are other unevaluated contexts, then what are they?
推荐答案
幸运的是,该标准提供了方便的列表(§5 [expr]¶8):
Fortunately, the standard has a handy list of those (§ 5 [expr] ¶ 8):
在某些情况下,出现未求值的操作数(5.2.8、5.3.3、5.3.7、7.1.6.2)。未评估的操作数不评估。未评估的操作数被视为完整表达式。
In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression.
让我们详细了解一下。
我将在示例中使用以下声明。声明的函数永远不会在任何地方定义,因此,如果对它们的调用出现在 evaluated 上下文中,则程序格式错误,并且会出现链接时错误。
I will use the following declarations in my examples. The declared functions are never defined anywhere so if a call to them appears in an evaluated context, the program is ill-formed and we will get a link-time error. Calling them in an unevaluated context is fine, however.
int foo(); // never defined anywhere
struct widget
{
virtual ~widget();
static widget& get_instance(); // never defined anywhere
};
typeid
§5.2.8 [expr.typeid]¶3:
typeid
§ 5.2.8 [expr.typeid] ¶ 3:
当
typeid时
应用于多态类类型的glvalue以外的表达式,结果引用的是std :: type_info
表示表达式静态类型的对象。左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)的转换不适用于表达式。如果表达式的类型是类类型,则该类应完全定义。 表达式是未计算的操作数
(第5条)。
When
typeid
is applied to an expression other than a glvalue of a polymorphic class type, the result refers to astd::type_info
object representing the static type of the expression. Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions are not applied to the expression. If the type of the expression is a class type, the class shall be completely-defined. The expression is an unevaluated operand (Clause 5).
请注意多态类(一个类
,其中至少有一个虚拟
成员)。
Note the emphasized exception for polymorphic classes (a class
with at least one virtual
member).
因此,没关系
typeid( foo() )
并为 int $产生
std :: type_info
对象c $ c>而这
and yields a std::type_info
object for int
while this
typeid( widget::get_instance() )
不是,可能会产生链接时错误。它必须评估操作数,因为动态类型是通过在运行时查找 vptr
来确定的。
is not and will probably produce a link-time error. It has to evaluate the operand because the dynamic type is determined by looking up the vptr
at run-time.
< rant>我感到非常困惑,即操作数的静态类型是否是多态的这一事实以这种戏剧性但微妙的方式改变了运算符的语义。< / rant>
<rant>I find it quite confusing that the fact whether or not the static type of the operand is polymorphic changes the semantics of the operator in such dramatic, yet subtle, ways.</rant>
§5.3.3 [expr.sizeof]¶1:
§ 5.3.3 [expr.sizeof] ¶ 1:
sizeof
运算符产生其操作数的对象表示形式中的字节数。 操作数可以是一个表达式,可以是未计算的操作数(第5条),也可以是带括号的 type-id 。sizeof
运算符不适用于具有函数或不完整类型的表达式,其基础类型在声明其所有枚举器之前未固定的枚举类型,
The
sizeof
operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is an unevaluated operand (Clause 5), or a parenthesized type-id. Thesizeof
operator shall not be applied to an expression that has function or incomplete type, to an enumeration type whose underlying type is not fixed before all its enumerators have been declared, to the parenthesized name of such types, or to a glvalue that designates a bit-field.
以下
sizeof( foo() )
非常好,相当于 sizeof(int)
。
sizeof( widget::get_instance() )
。但是请注意,它等效于 sizeof(widget)
,因此对于多态 return
类型可能不太有用。
is allowed too. Note, however, that it is equivalent to sizeof(widget)
and therefore probably not very useful on a polymorphic return
type.
§5.3.7 [ expr.unary.noexcept]¶1:
§ 5.3.7 [expr.unary.noexcept] ¶ 1:
noexcept
运算符确定是否其操作数(未评估的操作数(第5条))的评估会引发异常(15.1)。
The
noexcept
operator determines whether the evaluation of its operand, which is an unevaluated operand (Clause 5), can throw an exception (15.1).
表达式
noexcept( foo() )
有效,且评估为 false
。
此处
void bar() noexcept(noexcept( widget::get_instance() ));
请注意,只有内部 noexcept
是
§7.1.6.2 [dcl.type.simple]¶4.4:
§ 7.1.6.2 [dcl.type.simple] ¶ 4.4:
decltype
说明符是未求值的操作数(第5条)。
The operand of the
decltype
specifier is an unevaluated operand (Clause 5).
该语句
decltype( foo() ) n = 42;
声明类型为<$的变量 n
c $ c> int 并将其初始化为值42。
declares a variable n
of type int
and initializes it with the value 42.
auto baz() -> decltype( widget::get_instance() );
声明不带参数的函数 baz
和 return
sa widget&
。
declares a function baz
that takes no arguments and return
s a widget&
.
仅此而已有(从C ++ 14开始)。
And that's all there are (as of C++14).
这篇关于什么是C ++中未评估的上下文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!