Effective Modern C++ 条款2 理解auto类型推断
来源:互联网 发布:python 3程序开发指南 编辑:程序博客网 时间:2024/04/30 16:25
理解auto类型推断
如果你已经阅读了条款1,那么你基本上已经知道auto的规则了,因为除了一个奇怪的例外,auto的类型推断与模板类型推断相同。
auto类型推断可以被我们转换成模板类型推断。
在条款1中 template <typename T>
void f(ParamType param);
然后我们调用函数 f(expr);
在这个调用中,编译器通过expr 来推断T 的类型和ParamType 的类型。
而当我们用auto来声明定义变量时, auto 在上面的模板中扮演着T 的角色,而变量的类型则是ParamType ,很容易用以下例子来说明 auto x = 27;
在这里 x 的类型是auto,而在另一个例子中 const auto cx = x;
x 的类型是const auto,还有 const auto &rx = x;
x的类型是const auto & ,在这些例子中,编译器就像对待模板推断一样来对待auto,而相应的模板函数如下
template <typename T>void func_for_x(T param);func_for_x(27); // auto x = 27template <typename T>void func_for_cx(const T param);func_for_cx(x); // const auto cx =xtemplate <typename T>void func_for_rx(const T& param);func_for_rx(x); // const auto& rx = x
所以我们才说,auto类型推断和模板类型推断基本相同,只有一个例外,这个例外我们很快就会讨论到。
在条款1的模板类型推断中,根据ParamType (也就是函数中实际参数的类型)的不同分成了三种情况,而在auto类型推断中,类型标识符的类型也就是ParamType,因此也分成三种情况。
- 类型标识符是指针或者引用,但是不是通用引用(universal reference)
- 类型标识符是通用引用(universal reference)
- 类型标识符既不是指针也不是引用
我们已经在第一个例子中看见情况1和情况3 auto x = 27;
// 情况3 const auto cx = x;
// 情况3 const auto &rx = x;
// 情况1
而第二种情况如下 auto&& uref1 = x;
// x是int类型而且是个左值,所以uref1的类型是int& auto&& uref2 = cx;
// cx是const int类型而且是个左值,所以uref2的类型是const int& auto&& uref3 = 27;
// 27是个右值,uref3的类型是int&&
条款1中关于数组和函数的讨论,在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 fun1 = someFunc;
// func1的类型是void (*)(int, double) auto &func2 = someFunc;
// func2的类型是void (&)(int, double)
所以说模板类型推断和auto类型推断真的很类似。
auto类型推断有一个地方和模板类型推断不一样。
当我们想声明定义一个int类型时,在C++98有两种选择 int x1 = 27;
int x2(27);
而在C++11之后,又多了两种声明定义方式 int x3 = { 27 };
int x4{ 27 };
这四种声明定义方式的结果都是相同的,一个int类型的值为27。
在条款5中会解释用auto声明定义比用具体类型好,所以在这里我们用auto代替int,如下 auto x1 = 27;
auto x2(27);
auto x3 = { 27 };
auto x4{ 27 };
而这样编译运行后,前两个表达式中的变量是类型为int,值为27;而后两个表达式的变量类型为std::initializer_list<int>
,该序列只有一个元素值为27。
这是因为auto类型推断中的一个特殊规则,当用auto声明定义的变量用一个封闭的大括号初始化时,auto会把这个变量推断为std::initializer_list类型。如果这样的变量无法推断类型(例如大括号内有不同类型的值),那么代码会报错: auto x5 = { 1, 2, 3.0 };
// 报错,
//无法推断std::initializer_list<T>
中的T 的类型
上面的代码有两次类型推断,一次是通过括号把x5推断为std::initilizer_list<T>
,然后再用括号中的内容推断T 的类型
在auto中对于大括号初始化只有一种规则,就是把变量的类型推断为initializer_list,而相同的大括号放到模板类型推断中,类型推断会失败,而且代码也会报错: auto x = { 11, 23, 9};
// x的类型为std::initializer_list<int>
template <typename T>
void f(T param);
f({ 11, 23, 9 });
// 报错,无法推断类型T
但是,如果你在模板中把参数的类型定为std::initializer_list<T>
,,然后让编译器来推断类型T,这时候代码是正确的: template <typename T>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 });
// 此时T 的类型会被推断为int,而initList的类型是std::initialzer_list<int>
所以,auto类型推断和模板类型推断的不同之处在于,auto会假定大括号初始化时表现为initializer_list,而模板类型推断不会这样做。
在C++14中,可以把函数的返回值类型或者lambdad中的参数用auto声明,但是这两种情况下,类型推断原则应用的是模板类型推断的规则,所以在这两种情况下使用大括号是错误的:
auto createInitList(){ return { 1, 2, 3 }; // 报错}
同理
std::vector<int> v;...auto resetV = [&v](const auto& newValue) { v = newValue; };...resetV({ 1, 2, 3}); // 报错
总结
要记住的两点
- auto类型推断与模板类型推断基本一致,不过auto会假定大括号是一个std::initializer_list,但是模板类型推断则不会。
- 当一个函数返回类型是auto或者在lambda的参数中使用auto时,它们的类型推断规则是用模板类型推断的规则,而不是auto类型推断。
- Effective Modern C++ 条款2 理解auto类型推断
- [effective modern c++][2]理解auto类型推断
- Effective Modern C++:Item 2 ->弄清auto类型推断
- 《Effective Modern C++》翻译--条款2: 理解auto自动类型推导
- Effective Modern C++ 条款1 理解模板类型推断
- [effective modern c++][1]理解模板类型推断
- Effective Modern C++ 条款9补完 理解模板类型推断
- Effective Modern C++ 条款6 当auto会推断出不合理的类型时使用显式类型初始化语法
- 《Effective Modern C++》翻译--条款1: 理解模板类型推导
- [effective modern c++][5]与其使用显示类型推断不如使用auto
- Effective Modern C++ :Item 1 -> 理解模板类型推断
- Effective Modern C++: Item 4 -> 知道如何查看推断类型
- 《Effective Modern C++》读书笔记(2) -- auto类型推导(auto type deduction)
- Effective Modern C++ 条款4 懂得如何查看已推断类型
- Effective Modern C++ Item2 理解auto类型推导
- 《Effective Modern C++》翻译--条款3: 理解decltype
- Effective Modern C++ 条款5 尽量用auto代替显式类型声明
- Effective Modern C++ : Item 6 -> 当auto推断出不想要的类型时,使用显式类型初始化语法
- 在VS2015中用C++创建MFC规则动态库DLL
- dl4j基本环境搭建(win7+64位jdk1.8+IDEA)
- laravel 社区 使用ModelFactory 生产测试数据 artisan 建表
- UVALive-7392 - Bundles of Joy【树型DP】【深搜】【好题】
- "两地三中心"的容灾解决方案
- Effective Modern C++ 条款2 理解auto类型推断
- K sum算法
- 占位符
- java面试题训练0807_字符串逆转及回文
- Android UI(CheckBox)详解
- java学习之路 之 高级类特性1-instanceof操作符、对象类型转换(造型)
- SpringMVC 无法获取连接报错
- 九度OJ-浙大1008最短路径问题
- apache安装、配置和卸载