int x; constint cx = 42; constint& crx = x; const S* p = new S();
typedefdecltype((x)) x_with_parens_type; //x_with_parens_type是"int&";x类型为"int",是lvalue(故添加"&"); typedefdecltype(x) x_type; //x_type是"int" auto a_p = (x); //a_p的类型是"int" auto a = x; //a的类型是"int"
typedefdecltype((cx)) cx_with_parens_type; //cx_with_parens_type是"const int&";cx类型为"const int",是lvalue(故添加"&"); typedefdecltype(cx) cx_type; //cx_type是"const int" auto b_p = (cx); //b_p的类型是"int" auto b = cx; //b的类型是"int"
typedefdecltype((crx)) crx_with_parens_type; //crx_with_parens_type是"const int&";crx类型为"const int&",是lvalue(故再添一个"&",然后引用折叠) typedefdecltype(crx) crx_type; //crx_type是"const int&" auto c_p = (crx); //c_p的类型是"int" auto c = crx; //c的类型是"int"
typedefdecltype((p->m_x)) m_x_with_parens_type; //m_x_with_parens_type是"const int&";p->m_x类型为"const int",是lvalue(故添加"&") typedefdecltype(p->m_x) m_x_type; //虽然p->m_x是const的(因为p是const的),但m_x_type是"int"(因为m_x的声明类型是"int",没const) auto d_p = (p->m_x); //d_p的类型是"int" auto d = p->m_x; //d的类型是"int"
例2:更复杂的情形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
const S foo(); constint& foobar(); std::vector<int> vect = {42, 43};
typedefdecltype(foo()) foo_type; //foo_type是"const S";foo()的类型为"const S",是prvalue(故不加"&") auto a = foo(); //a的类型是"S",const被剥除
typedefdecltype(foobar()) foobar_type; //foobar_type是"const int&";foobar()的类型是"const int&",是lvalue(故再添一个"&",然后引用折叠) auto b = foobar(); //b的类型是"int",const和"&"被剥除;
typedefdecltype(vect.begin()) iterator_type; //iterator_type是"vector<int>::iterator";vect.begin()的类型为"vector<int>::iterator",是prvalue(故不加"&") auto iter = vect.begin(); //iter的类型是"vector<int>::iterator"
decltype(vect[0]) first_element = vect[0]; //类型是"int&";operator[]返回类型为"int&",是lvalue(故再添一个"&",然后引用折叠) auto second_element = vect[1]; //类型是"int",因为"&"被剥除;
int x = 0; int y = 0; constint cx = 42; constint cy = 43; double d1 = 3.14; double d2 = 2.72;
typedefdecltype(x * y) prod_xy_type; //prod_xy_type是"int";乘积的类型为"int",且为prvalue(故不加"&") auto a = x * y; //a的类型是"int"
typedefdecltype(cx * cy) prod_cxcy_type; //prod_cxcy_type是"int";乘积的类型为"int"(注意不是const int),且为prvalue(故不加"&") auto b = cx * cy; //b的类型是"int"
typedefdecltype(d1 < d2 ? d1 : d2) cond_type; //cond_type是"double&";运算结果类型是"double",且为lvalue(故添加"&") auto c = d1 < d2 ? d1 : d2; //c的类型是"double"
//注意:x < d2 ? x : d2的结果是prvalue,因为这个表达式可能返回x,也可能返回d2,它们是不同的类型,为此 //编译器分配一个临时变量(double)来存结果;若返回x,x被升级为double; typedefdecltype(x < d2 ? x : d2) cond_type_mixed; //cond_type_mixed是"double";运算结果类型是"double",且为prvalue(故不加"&") auto d = x < d2 ? x : d2; //d的类型是"double"
//失败的尝试 template<typename T, typename S> auto fpmin(T x, S y) -> decltype(x < y ? x : y) { return x < y ? x : y; }
暂不提auto -> decltype(...)这种语法,下文会介绍。为什么这是个失败的尝试呢?
因为返回类型decltype(x < y ? x : y)可能是引用(T和S相同的时候),也可能不是(T和S不同的时候)。而若是前一种情况(返回引用的时候),大错就铸成了:因为返回的是局部变量(函数参数x或y)的引用。玩C++的人都知道,这是很幼稚的错误。然而,在这里它却如此的隐晦。正确的版本是:
1 2 3 4 5 6
//正确的版本 template<typename T, typename S> auto fpmin(T x, S y) -> typename std::remove_reference<decltype(x < y ? x : y)>::type { return x < y ? x : y; }