auto和decltype

auto:

auto能让编译器通过初始值来推算变量的类型。显然auto定义的变量必须有初始值:

1 int val1 =1;
2 
3 int val2 = 2;
4 
5 auto cnt = val1 + val2;//val1+val2的结果是int类型,因此cnt也是int类型

使用auto也能在一条语句中声明多个变量。因为一条语句只能有一个基本类型,所以该语句中所有变量的初始值的变量类型必须一致:

1 auto cnt1 = 1, cnt2 = 1;//正确
2 
3 auto x1 = 0, x2 = 3.14;//错误

复合类型,常量和auto:

编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。

当引用被当作auto的初始值时,真正参与初始化的其实是引用的对象的值。此时编译器以引用对象的类型作为auto的类型:

int cnt = 1, &x = cnt;

auto y = x;//y是int类型,和x的引用对象cnt一致

auto一般会忽略掉顶层const,保留底层const,比如初始值是一个指向常量的指针时:

 1 int cc = 0;
 2 
 3 const int cnt = cc, &x = cnt;
 4 
 5 auto a = cnt;//a是一个int类型(cnt的顶层const被忽略掉了)
 6 
 7 auto b = x;//b是一个int类型,x是cnt的别名,而x是一个顶层const
 8 
 9 auto c = &cc;//c是一个指向int变量的指针(int变量的地址就是指向int类型的指针)
10 
11 auto d = &cnt;//d是一个指向int常量的指针(对常量对象取地址是一种底层const)
12 
13 //如果希望推断出的auto类型是一个顶层const,需要明确指出
14 
15 const auto e = cnt;//cnt推演类型是int,e的类型是const int
 1 int cnt = 2;
 2 
 3 int cc = 1;
 4 
 5 const int *x = &cnt;
 6 
 7 auto y = x;
 8 
 9 // *y += 1;//底层const保留了,所以y和x一样是一个指向常量cnt的指针,不能通过改变y来修改cnt的值
10 
11 cout << x << " " << y << endl;//x和y的值相同,都是存储的cnt的地址
12 
13 int *const p = &cnt;
14 
15 auto gg = p;//顶层const被忽略了,即gg是一个指向int的指针
16 
17 gg = &cc;//所以gg的值可以修改,即gg可以指向其他对象

还可以将引用的类型设置为auto,此时原来的初始化规则仍然适用:

1  const int cnt = 1;
2 
3 auto &a = cnt;//a是一个int常量引用,绑定到cnt
4 
5 //auto &b = 1024;//错误,不能非常量引用绑定字面值
6 
7 const auto &b = 1024;//可以为常量引用绑定字面值

通过上面第二条语句还可以发现设置一个类型为auto的引用时,初始值中的顶层const仍然保留。但是给初始值绑定一个常量引用则此时顶层常量会被忽略。

decltype:

有时会遇到这种情况:希望从表达式的类型推断出要定义的变量的类型,但是不想用该变量的表达式初始化变量。为了满足这一要求,c++11标准引入了类型说明符decltype,它的作用时选择并返回操作数的数据类型。在此过程中,编译器会分析表达式并得到它的类型,却不实际计算表达式的值:

decltype(f()) sum = x;//sum的类型就是函数 f 的返回类型

编译器并不实际调用函数 f,而是使用当调用发生时 f 的返回值类型作为 sum 的类型。

decltype 处理顶层 const  和引用的方式与 auto 有些许不同。如果 decltype 使用的表达式是一个变量,则 decltype 返回该变量的类型(包括顶层 const 和引用在内):

1 const int x = 0, &cnt = x;
2 
3 decltype(x) a = 0;//a的类型是const int
4 
5 decltype(cnt) b = a;//b的类型是const int&, 绑定的对象是a
6 
7 // decltype(cnt) c;//c是一个引用,必须初始化

值得注意的是引用从来都是作为其所绑定对象的同义词出现,只有在 decltype 处是一个例外。

如果 decltype 使用的表达式不是一个变量,则 decltype 返回表达式结果对应的类型:

1 int cnt = 1024, *p = &cnt, &r = cnt;
2 
3 decltype(r + 0) b;//r + 0的结果是一个int类型,因此b是一个为初始化的int变量
4 
5 decltype(*p) c;//错误,c是int&类型,必须初始化

通过第三条语句可以发现,如果表达式的内容是解引用操作,则 decltype 将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指的对象,而且还能给这个对象赋值。因此 decltype(*p) 的结果类型是 int&,而非 int。

还需要特别当心的是,decltype 的结果类型与表达式形式密切相关。对于 decltype 所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加是有区别的。后者得到的结果就是表达式结果的类型,而前者得到的类型一定是引用类型。因为如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的 decltype 就会得到引用类型:

1 int cnt = 0, x = 1024;
2 
3 decltype(cnt) a;//a是一个int类型变量
4 
5 decltype((cnt)) b = x;//b是一个int&类型
6 
7 decltype(((cnt))) c = x;//c是一个int&类型
原文地址:https://www.cnblogs.com/geloutingyu/p/7898334.html