《Effective Modern C++》读书笔记(2) -- auto类型推导(auto type deduction)
2017-05-18 12:52
866 查看
模板类型推导涉及模板(template),函数(functinos)和参数(parmeters),但是auto并没有处理处理这些问题。
对于auto而言,它的强大之处在于类型推导(type deduce),因此既然是推导,那么它就不能像普通的变量一样,只声明不定义,例如:
即使auto在这方面有些许欠缺,但依然不能阻止我们使用它。
和模板类型推导相似,这里也有三种情况
类型说明符是一个指针(pointer)或者引用(reference),但不是一个通用引用(universal reference)
类型说明符是一个通用引用(universal reference)
类型说明符既不是指针也不是引用
模板类型推导中,讨论了一个数组或者一个函数名传递的推导,在auto中也是一样的
例如:
对于:
1. uref1
x的类型是int并且是左值(lvalue),所以uref1的类型是int&
uref2
cx的类型是const int并且是左值(lvalue),所以uref2的类型是const int&
uref3
27的类型是int并且是右值(rvalue),所以uref3的类型是int&&
对于引用,这里有一个重要的知识点:引用折叠(至于具体的内容,可以先自行查阅资料,之后会讲这点),这里简单举个栗子。
例如:
当我们这样使用auto的时候,
当我们声明
即用一个左值初始化w1,因此编译器就会将Widget&这个类型推到给auto说明符,替换之后,代码变成:
通过引用折叠,最后变成
所以w1的类型为左值引用,即Widget&
回到上面说的,为什么uref3的类型为int&&呢,重新看一下代码
27是一个右值,因此编译器就会将int&&这个类型推到给auto说明符,替换之后,代码变成:
通过引用折叠,最后变成
答案就出来了
C++11又加了两种(通过初始化列表):
它们都只产生一种情况:一个整形,其值为27
但是当我们使用auto类型说明符的时候,情况就有点不同了。例如:
对于前面两种,结果是:声明一个整形变量,其值为27
对于后面两种,结果是:声明一个类型为
的容器,包含一个值为27的元素
很奇怪不是嘛?记住就行,这是auto的一个特殊推导规则。
例如,我们可以这样写:
x6错误是由于std::initializer_list是一个模板类,前面讲了模板的推导,需要推导T和ParamType的类型
这里产生了歧义,即int和double类型。无法确定唯一的T
只能改成:
但在C++14中,你可以使用第一种方法。C++14允许auto推导函数的返回类型,lambda也可以在参数列表中使用auto。
auto类型推导
auto作为C++11新添加的特性之一,很强大,即便有些许不足,但是也是瑕不掩瑜。对于auto而言,它的强大之处在于类型推导(type deduce),因此既然是推导,那么它就不能像普通的变量一样,只声明不定义,例如:
int a; // 声明变量a为一个整形,没有定义 auto a; // 错误,无法推导出变量a的类型 auto a = 1; // 正确,a的类型为整形
即使auto在这方面有些许欠缺,但依然不能阻止我们使用它。
和模板类型推导相似,这里也有三种情况
类型说明符是一个指针(pointer)或者引用(reference),但不是一个通用引用(universal reference)
类型说明符是一个通用引用(universal reference)
类型说明符既不是指针也不是引用
类型说明符是一个指针(pointer)或者引用(reference),但不是一个通用引用(universal reference)
例如:int a = 27; auto& rx = a; // rx是一个引用,它的类型为int&
模板类型推导中,讨论了一个数组或者一个函数名传递的推导,在auto中也是一样的
例如:
const char name[] = "R. N. Briggs"; auto arr1 = name; // arr1是一个指针,它的类型为const char* auto& arr2 = name; // arr2是一个引用,它的类型为const char (&)[13] void someFunc(int, double); auto func1 = someFunc; // func1的类型是void (*)(int, double) auto& func2 = someFunc; // func2的类型是void (&)(int, double)
类型说明符是一个通用引用(universal reference)
当我们写下:auto x = 27; const auto cx = x; const auto& rx = x; auto&& uref1 = x; auto&& uref2 = cx; auto&& uref3 = 27;
对于:
1. uref1
x的类型是int并且是左值(lvalue),所以uref1的类型是int&
uref2
cx的类型是const int并且是左值(lvalue),所以uref2的类型是const int&
uref3
27的类型是int并且是右值(rvalue),所以uref3的类型是int&&
对于引用,这里有一个重要的知识点:引用折叠(至于具体的内容,可以先自行查阅资料,之后会讲这点),这里简单举个栗子。
例如:
Widget w; // 声明一个不知道是什么的类
当我们这样使用auto的时候,
auto&& w1 = w; // 这时候就会发生引用折叠
当我们声明
auto&& w1 = w;
即用一个左值初始化w1,因此编译器就会将Widget&这个类型推到给auto说明符,替换之后,代码变成:
Widget& && w1 = w; // 这里有三个(&)符号
通过引用折叠,最后变成
Widget& w1 = w;
所以w1的类型为左值引用,即Widget&
回到上面说的,为什么uref3的类型为int&&呢,重新看一下代码
auto&& uref3 = 27;
27是一个右值,因此编译器就会将int&&这个类型推到给auto说明符,替换之后,代码变成:
int&& && uref3 = 27; // 这里有四个(&)符号
通过引用折叠,最后变成
int&& uref3 = 27;
答案就出来了
类型说明符既不是指针也不是引用
先说下在C++11之前,如果声明一个变量为整形并为它赋初值,有两种方法:int x1 = 27; // 方法一 int x2(27); // 方法二
C++11又加了两种(通过初始化列表):
int x3 = { 27 }; // 方法三 int x4{ 27 }; // 方法四
它们都只产生一种情况:一个整形,其值为27
但是当我们使用auto类型说明符的时候,情况就有点不同了。例如:
auto x1 = 27; auto x2(27); auto x3 = { 27 }; autox4{ 27 };
对于前面两种,结果是:声明一个整形变量,其值为27
对于后面两种,结果是:声明一个类型为
std::initializer_list<int>
的容器,包含一个值为27的元素
很奇怪不是嘛?记住就行,这是auto的一个特殊推导规则。
例如,我们可以这样写:
auto x5 = {1, 2, 3}; auto x6 = {1, 2, 3.0}; // 错误
x6错误是由于std::initializer_list是一个模板类,前面讲了模板的推导,需要推导T和ParamType的类型
这里产生了歧义,即int和double类型。无法确定唯一的T
auto,lambda和函数返回类型
在C++11中,这些都是迷!!例如,你不能这样写:#include <iostream> template <typename T> auto func(T i) { return i; } int main(int argc, char const *argv[]) { int a = func<int>(2); std::cout << a << std::endl; return 0; }
只能改成:
#include <iostream> template <typename T> auto func(T i) -> decltype(i) { return i; } int main(int argc, char const *argv[]) { int a = func<int>(2); std::cout << a << std::endl; // 输出:2 return 0; }
但在C++14中,你可以使用第一种方法。C++14允许auto推导函数的返回类型,lambda也可以在参数列表中使用auto。
相关文章推荐
- 《Effective Modern C++》读书笔记(1) -- 模板类型推导(template type deduction)
- 《Effective Modern C++》翻译--条款2: 理解auto自动类型推导
- Effective Modern C++翻译(3)-条款2:明白auto类型推导
- 《Effective Modern C++》翻译--条款2: 理解auto自动类型推导
- Effective Modern C++之Item 2 理解auto的类型推导
- Effective Modern C++ Item2 理解auto类型推导
- 《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导
- 《Effective Modern C++》读书笔记(4) -- 尽量使用auto来显式类型声明
- Effective Modern C++ Item1 模板类型推导详解
- [effective modern c++][2]理解auto类型推断
- Effective Modern C++: Item 5 -> 优先选择auto而不是显式类型声明
- Effective Modern C++ 条款5 尽量用auto代替显式类型声明
- Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型
- 《Effective Modern C++》翻译--条款4:了解如何查看推导出的类型
- [effective modern c++][5]与其使用显示类型推断不如使用auto
- 《effective modern c++》笔记之c++类型推导(1)
- Effective Modern C++ 条款2 理解auto类型推断
- 《Effective Modern C++》翻译--条款1: 理解模板类型推导
- 《Effective Modern C++》翻译--条款4:了解如何查看推导出的类型
- <Effective Mordern C++>笔记:Item 2:Understand auto type deduction.