C++11 decltype关键字

来源:互联网 发布:qq飞车白银帝王数据 编辑:程序博客网 时间:2024/06/05 03:43

1.1 decltype语法

在C++11中增加了decltype关键字(表达式:decltype(exp)),用来在编译时推导出一个表达式的类型,并且不会真正计算表达式的值。
int x = 0;decltype(x) y = 1;//y->intdecltype(x + y) z = 0;//z->intconst 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的类型一致

class Foo{public:static const int num=0;int x;};int n=0;volatile const int &x = n;//volatile:直接存取原始内存地址decltype(n) a = n;//a->intdecltype(x) b = n;;//b->const int&decltype(Foo::num) c = 0;//c->const intFoo foo;decltype(foo.x) d = 0;//d->int, 类访问表达式

(2)exp是函数调用,decltype(exp)和返回值的类型一致
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);//纯右值//testint 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->intdecltype(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->intdecltype((foo.x)) b = a;//b->const int&int n=0, m=0;decltype(m+n) c = 0;//c->intdecltype((m+=n)) d = c;//d->int&
m+n返回一个右值,按照规则3, decltype的结果为int
m+=n返回一个左值,按照规则3,decltype的结果为int&(左值返回引用)

1.3 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;