C++ Primer 第 5 版第 16.5 章 Class- 模板特化
C++ Primer 5th Edition Chapter 16.5 Class-Template Specializations
我认为这本书的第 711 页有错误:
In § 16.2.3 (p. 684) we introduced the library remove_reference
type. That template works through a series of specializations:
// 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;
All three variables, a
,b
,and c
, have type int
.
我认为 decltype(i)
会产生一个普通的 int
而不是 int&
因此在 b
的情况下实际上使用了最通用的模板。对于普通变量类型 [1],decltype
类型说明符生成普通类型,对于其他可用作 lvalue
的表达式,它将生成 [=26] =].
例子
#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
.
- If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then
decltype
yields the type of the entity named by this expression.
另一方面,decltype((i))
产生类型 int&
; (i)
被视为左值表达式。
- If the argument is any other expression of type
T
, and
b) if the value category of expression is lvalue, then decltype yields T&
;
Note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus decltype(x)
and decltype((x))
are often different types.
我认为这本书的第 711 页有错误:
In § 16.2.3 (p. 684) we introduced the library
remove_reference
type. That template works through a series of specializations:// 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;
All three variables,
a
,b
,andc
, have typeint
.
我认为 decltype(i)
会产生一个普通的 int
而不是 int&
因此在 b
的情况下实际上使用了最通用的模板。对于普通变量类型 [1],decltype
类型说明符生成普通类型,对于其他可用作 lvalue
的表达式,它将生成 [=26] =].
例子
#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
.
- If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then
decltype
yields the type of the entity named by this expression.
另一方面,decltype((i))
产生类型 int&
; (i)
被视为左值表达式。
- If the argument is any other expression of type
T
, and
b) if the value category of expression is lvalue, then decltype yieldsT&
;
Note that if the name of an object is parenthesized, it is treated as an ordinary lvalue expression, thus
decltype(x)
anddecltype((x))
are often different types.