1.1 decltype语法
在C++11中增加了decltype关键字(表达式:decltype(exp)),用来在编译时推导出一个表达式的类型,并且不会真正计算表达式的值。
int x = 0;
decltype(x) y = 1; //y->int
decltype(x + y) z = 0; //z->int
const int& i = x;
decltype(i) j = y; //j->const int&
const decltype(z) *p = &z; //*p->const int, p->const int*
decltype(z) *pi = &z; //*pi->int, pi->int*
decltype(pi) * pp = π //*pp->int*, pp->int**
1.2 decltype的推导规则
表达式:decltype(exp)
(1)exp是标识符、类访问表达式,decltype(exp)和exp的类型一致
(2)exp是函数调用,decltype(exp)和返回值的类型一致
(3)其它情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则和exp类型一致.(左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式))
带括号的表达式和加法运算表达式
m+=n返回一个左值,按照规则3,decltype的结果为int&(左值返回引用)
(1)exp是标识符、类访问表达式,decltype(exp)和exp的类型一致
class Foo
{
public:
static const int num=0;
int x;
};
int n=0;
volatile const int &x = n; //volatile:直接存取原始内存地址
decltype(n) a = n; //a->int
decltype(x) b = n;; //b->const int&
decltype(Foo::num) c = 0; //c->const int
Foo foo;
decltype(foo.x) d = 0; //d->int, 类访问表达式
int& func_int_r(void); //左值(可以理解为可寻址值)
int&& func_int_rr(void); //x值
int func_int(void); //纯右值
const int& func_cint_r(void); //左值
const int&& func_cint_rr(void); //x值
const int func_cint(void); //纯右值
const Foo func_cfoo(void); //纯右值
//test
int x = 0;
decltype(func_int_r()) a1 = x; //a1->int&
decltype(func_int_rr()) b1 = 0; //b1->int&&
decltype(func_int()) c1 = 0; //c1->int,对于纯右值而言,只有类类型可以携带const修饰符,此外的一般忽略掉const属性
decltype(func_cint_r) a2 = x; //a2->const int&
decltype(func_cint_rr()) b2 = 0; //b1->const int&&
decltype(func_cint()) c2 = 0; //c1->int
decltype(func_cfoo()) ff = Foo(); //ff->const Foo
(3)其它情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则和exp类型一致.(左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式))
带括号的表达式和加法运算表达式
struct Foo
{
int x;
};
const Foo foo = Foo();
decltype(foo.x) a = 0; //a->int
decltype((foo.x)) b = a; //b->const int&
int n=0, m=0;
decltype(m+n) c = 0; //c->int
decltype((m+=n)) d = c; //d->int&
m+n返回一个右值,按照规则3, decltype的结果为intm+=n返回一个左值,按照规则3,decltype的结果为int&(左值返回引用)
1.3 decltype应用场景
decltype多应用在泛型编程之中,例如如下的代码:
但是需要const迭代器的时候,就需要对代码进行维护了,为代码加入const迭代器
但是在使用了decltype之后就不要这样了,上面的代码可以写成
实际上,标准库中有些类型都是通过decltype来定义的:
template<typename T> class
{
typename T::iterator it;
void func(T t)
{
it = t.begin(); //这里取它迭代器的首位置
}
};
但是需要const迭代器的时候,就需要对代码进行维护了,为代码加入const迭代器
template<typename T> class
{
typename T::const_iterator it;
void func(T t)
{
it = t.begin(); //这里取它迭代器的首位置
}
};
但是在使用了decltype之后就不要这样了,上面的代码可以写成
template<typename T> class
{
decltype(T.begin()) it;
void func(T t)
{
it = t.begin(); //这里取它迭代器的首位置
}
};
实际上,标准库中有些类型都是通过decltype来定义的:
typedef decltype(nullptr) nullptr_t;
typedef decltype(sizeof(0)) size_t;