问题描述
我认为这本书的第 711 页有错误:
在 § 16.2.3 (p. 684) 中,我们引入了库 remove_reference
类型。该模板通过一系列专业化工作:
// original,most general template
template <class T> struct remove_reference {
typedef T type;
};
// partial specializations that will be used fore lvalue and rvalue references
template <class T> struct remove_reference<T&> // lvalue references
typedef T type;
};
template <class T> struct remove_reference<T&&> // rvalue references
typedef T type;
};
...
int i;
// declyptype(42) is int,used the original template
remove_reference<decltype(42)>::type a;
// decltype(i) is int&,uses first(T&) partial specialization
remove_reference<decltype(i)>::type b;
// delctype(std::move(i)) is int&&,uses second (i.e.,T&&) partial specialization
remove_reference<decltype(std::move(i))>::type c;
所有三个变量 a
、b
和 c
的类型均为 int
。
我认为 decltype(i)
产生一个普通的 int
而不是 int&
因此最通用的模板实际上在 b
的情况下使用。对于普通变量类型 [1],decltype
类型说明符产生普通类型,而对于其他可以用作 lvalue
的表达式,它将产生和 lvalue reference
。
示例
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
template <typename T> struct blubb {
typedef T type;
void print() { cout << "plain argument type\n"; }
};
template <typename T> struct blubb<T&> {
typedef T type;
void print() { cout << "lvalue reference type\n"; }
};
template <typename T> struct blubb<T&&> {
typedef T type;
void print() { cout << "rvalue reference type\n"; }
};
int main() {
int i = 0;
blubb<decltype(42)> plain;
plain.print();
blubb<decltype(i)> lvalue_ref; // actually not!
lvalue_ref.print();
int* pi = &i;
blubb<decltype(*pi)> lvalue_ref2; // expression which can be on the left hand side
lvalue_ref2.print();
blubb<decltype(std::move(i))> rvalue_ref;
rvalue_ref.print();
return 0;
}
编译运行
g++ -o types types.cpp -Wall -pedantic -g && ./types
plain argument type
plain argument type
lvalue reference type
rvalue reference type
请告诉我我是对还是错,并在适当时解释。
谢谢
[1] 可能正确的术语是 id-expression
?
解决方法
是的,对于不带括号的 id-expression,decltype
产生由 id-expression 命名的实体类型,然后 decltype(i)
产生类型 int
。
- 如果参数是无括号的 id 表达式或无括号的类成员访问表达式,则
decltype
产生由此表达式命名的实体的类型。
另一方面,decltype((i))
产生类型 int&
; (i)
被视为左值表达式。
- 如果参数是
T
类型的任何其他表达式,并且
b) 如果表达式的值类别是左值,则 decltype 产生T&
;
请注意,如果对象的名称被括号括起来,则它被视为普通的左值表达式,因此 decltype(x)
和 decltype((x))
通常是不同的类型。