什么表达式在应用decltype时生成引用类型? 我正在阅读C++的底漆,当表达式产生一个对象类型,当它给对象产生一个引用类型时,它不能理解。
我引用书中的话:什么表达式在应用decltype时生成引用类型? 我正在阅读C++的底漆,当表达式产生一个对象类型,当它给对象产生一个引用类型时,它不能理解。,c++,c++11,decltype,C++,C++11,Decltype,我引用书中的话: 当我们将decltype应用于一个非变量的表达式时,我们得到了该表达式产生的类型 一般来说,decltype为产生 可以位于指定左侧的对象 考虑到以下准则: int i = 3, *ptr = &i, &ref = i; decltype(ref + 0) j; 在上述代码中,表达式“ref+0”导致对ref所指对象的值i和0进行相加的固有操作。因此,按照第一条规则,表达式将生成int类型。 但是按照第二条规则,由于表达式生成的对象类型可以位于赋值的左侧(在本
int i = 3, *ptr = &i, &ref = i;
decltype(ref + 0) j;
在上述代码中,表达式“ref+0”导致对ref所指对象的值i和0进行相加的固有操作。因此,按照第一条规则,表达式将生成int类型。
但是按照第二条规则,由于表达式生成的对象类型可以位于赋值的左侧(在本例中为int),decltype不应该生成ref-to-int(int&)类型吗
书中还说,对于以下代码
decltype(*ptr) k;
k的类型是int&而不是int,表达式产生的类型
它还表示,对于下面代码中的赋值表达式
decltype(a = b) l;
l将具有赋值操作左侧对象的引用类型
我们如何知道哪些表达式产生对象类型,哪些表达式产生对对象类型的引用?对于表达式,如示例中所示,如果参数为左值,decltype将提供引用类型 7.1.6.2p4:
The type denoted by decltype(e) is defined as follows:
— if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
— otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
— otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
— otherwise, decltype(e) is the type of e.
The operand of the decltype specifier is an unevaluated operand (Clause 5).
[ Example:
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = i; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4 = x3; // type is const double&
—end example ]
要理解这些概念而不正式是不容易的。初级读物可能不想让您感到困惑,并且避免引入诸如“左值”、“右值”和“xvalue”之类的术语。不幸的是,为了理解
decltype
的工作原理,这些都是基础
首先,求值表达式的类型决不是引用类型,也不是顶级const
-非类类型的限定类型(例如int-const
或int&
)。如果表达式的类型被证明是int&
或int const
,则在进一步计算之前,它会立即转换为int
这在C++11标准的第5/5和5/6段中有规定:
5如果表达式最初具有类型“引用T”(8.3.2,8.5.3),则该类型在
任何进一步的分析。表达式指定由引用表示的对象或函数,以及
表达式是左值或X值,具体取决于表达式
6如果prvalue最初的类型为“cv T”,其中T
是cv非限定非类、非数组类型,则
在进一步分析之前,将表达式调整为T
表达就到此为止。decltype
做什么?确定给定表达式e
的decltype(e)
结果的规则在第7.1.6.2/4段中规定:
decltype(e)
表示的类型定义如下:
-如果e
是未加密的id表达式或未加密的类成员访问(5.2.5),decltype(e)
是由e
命名的实体的类型。如果没有这样的实体,或者如果e
命名了一组重载函数,
该计划形式不合理
-否则,如果e
是一个x值,decltype(e)
是T&
,其中T
是e
的类型
-否则,如果e
是左值,decltype(e)
是T&
,其中T
是e
的类型
-否则,decltype(e)
是e
的类型
decltype
说明符的操作数是未赋值的操作数(第5条)
这听起来确实令人困惑。让我们试着一部分一部分地分析它。首先:
-如果e
是未加密的id表达式或未加密的类成员访问(5.2.5),decltype(e)
是由e
命名的实体的类型。如果没有这样的实体,或者如果e
命名了一组重载函数,
该计划形式不合理
这很简单。如果e
只是一个变量的名称,而您没有将其放在括号内,则decltype
的结果就是该变量的类型。所以
bool b; // decltype(b) = bool
int x; // decltype(x) = int
int& y = x; // decltype(y) = int&
int const& z = y; // decltype(z) = int const&
int const t = 42; // decltype(t) = int const
请注意,这里的decltype(e)
的结果不一定与计算表达式e
的类型相同。例如,表达式z
的求值产生类型为int const
,而不是int const&
(因为在第5/5段中,&
被剥离,正如我们前面所看到的)
让我们看看当表达式不仅仅是标识符时会发生什么:
-否则,如果e
是一个x值,decltype(e)
是T&
,其中T
是e
的类型
这越来越复杂了。什么是xvalue?基本上,它是表达式可以属于的三个类别之一(xvalue、lvalue或prvalue)。当调用返回类型为右值引用类型的函数时,或者作为对右值引用类型进行静态转换的结果时,通常会获得xvalue。典型的例子是调用std::move()
使用标准中的措辞:
[注意:如果表达式是:
-隐式或显式调用返回类型为右值引用的函数的结果
对于对象类型
-对对象类型的右值引用的强制转换
-一种类成员访问表达式,指定非引用类型的非静态数据成员,其中
对象表达式是一个xvalue,或
-a公司
int x; // decltype(std::move(x)) = int&&
// decltype(static_cast<int&&>(x)) = int&&
int x; // decltype(x) = int (as we have seen)
// decltype((x)) = int& - here the expression is parenthesized, so the
// first bullet does not apply and decltype appends & to the type of
// the expression (x), which is int
int& foo() { return x; } // decltype(foo()) = int&
int foo() { return x; } // Function calls for functions that do not return
// a reference type are prvalue expressions
// decltype(foo()) = int
// decltype(42) = int
int i = 3, *ptr = &i, &ref = i;
decltype(ref + 0) j;
decltype(*ptr) k;
decltype(a = b) l;
int foo() { return 42; }
foo() = 24; // ERROR! foo() is a prvalue expression, cannot be on the left
// side of an assignment