《Effective Modern C++》读书笔记 Item 2 auto的类型推导

注意:

还要学习一个

↑↑↑↑ 这样的方框里的片段完全不来自于原书,而是我自己的理解。

Item 2 Understand auto type deduction - auto类型推导

在C++11之前,auto 关键字一直是用于声明自动储存类型的变量时使用的,基本上没有什么实际作用,地位和 export 关键字(用于向编译单元之外导出模板,也在C++11中被取消)类似。

在C++11中,auto 终于不再废材,终于具备了类似C#中 var 关键字的效果,可以自动推导出变量的类型,可以少打几个字了:

var map = Dictionary<string, List<string>>();

当用 auto 声明变量时,声明的类型可以和Item1ParamType 例子对应起来:

template<typename T>
void f(ParamType param);   // Item1的例子

auto x = 27;
const auto cx = x;
const auto& rx = x;

其中 auto 就代替了原本 T 这个类型参数的位置,诸如 const auto& 的部分就构成了 ParamType 这一部分。也以此能推导出 auto 所代表的类型。

同样,auto 的推导,也有三种情形:

  1. 整个类型部分(ParamType 部分)是指针或引用,但不是universal引用;
  2. 类型部分是universal引用;
  3. 类型部分不是指针也不是引用

其中情形2的表现也和Item1中的类型推导是一样的:

auto x = 27;
const auto cx = x;
const auto& rx = x;

auto&& uref1 = x;  // 绑定到左值,uref1int&
auto&& uref2 = cx; // 绑定到const左值,uref2const int&
auto&& uref3 = 27; // 绑定到右值,uref3int&&

universal引用用于尚未确定类型、需要类型推导的类型表达式上,指定这一类型是引用,然后编译器自动推导出符合规则的、最合适的引用类型。

另外,数组名和函数名的退化,也能用 auto& 避免:

const char name[] ="R. N. Briggs";  // type: const char[13]

auto arr1 = name;  // 退化到: const char*
auto& arr2 = name; // 不退化: const char (&)[13]

auto 需要注意的语法点

C++新增了新的初始化语法,那就是使用 {} 进行初始化。但C++11也增加了 initializer_list 这个模板,使得使用 auto 进行类型推导时要注意:

auto x1 = 27;     // x1 是 int
auto x2(27);      // 同上,通过()初始化
auto x3 = { 27 }; // x3 是 std::initializer_list<int>,其值是 { 27 }
auto x4{ 27 };    // 同上

“大括号初始化列表(braced-init-list)”在 auto 和 使用冒号的for循环(Range-based for loop)中,会构造成 initializer_list

参考 http://en.cppreference.com/w/cpp/utility/initializer_list

同时,出现不同类型的变量会导致 initializer_list<T> 无法进行 T 的类型推导:

auto x5 = { 1, 2, 3.0 }; // 错误

x5 先因 auto 被推导为 initializer_list<T>,进而导致 T 的推导失败。

对大括号初始器的处理,是 auto 和模板在类型推导上唯一的不同:

auto x = { 11, 23, 9 };  // ok

template<typename T>
void f(T param);
f({ 11, 23, 9 });        // 错误,模板不认大括号!不能推导 T

不过可以指明 param 的类型是 initializer_list

template<typename T>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 }); // T -> int, ParamType -> std::initializer_list<int>

auto 假设大括号初始列表是 initializer_list,而模板不进行这样的假设。

在C++14中,auto关键字 可以用于函数返回值推导,以及用于 lambda 表达式的形参类型声明。而在这两种用法中,auto关键字 实行模板类型推导规则,而不是 auto 类型推导规则,即此时的 auto 不能推导成 initializer_list

auto createInitList()
{
    return { 1, 2, 3 };  // auto 推导返回值,会失败
}

std::vector<int> v;
auto resetV = [&v](const auto& newValue) { v = newValue; }; // auto 用于声明lambda表达式形参类型
resetV({ 1, 2, 3 });  // 同样失败 

此条款的注意点

  1. auto 类型推导规则基本和模板类型推导规则一样,唯一不同是 auto 假设大括号代表 initializer_list
  2. auto关键字 在返回值和lambda表达式形参推导时,执行模板类型推导规则。
时间: 2024-10-04 15:29:53

《Effective Modern C++》读书笔记 Item 2 auto的类型推导的相关文章

Effective Modern C++ 读书笔记 Item 1

最近发现了<Effective Modern C++>这本书,作者正是大名鼎鼎的Scott Meyers——<Effective C++>.<Effective STL>的作者. 而就在C++11逐渐普及,甚至是C++14的新特性也进入大家的视野的时候,<Effective Modern C++>一书应运而生.此书与其前辈一样,通过数十个条款来展开,只不过这次是集中于C++11和C++14的新特性.auto.decltype.move.lambda表达式……

《Effective Modern C++》翻译--条款1: 理解模板类型推导

北京2016年1月9日13:47:17 开始第一章的翻译. 第一章名为 类型推断 分为四个条款: 1理解模板类型推导 2理解auto自动类型推导 3理解decltype操作符 4如何对待推导的类型 第一章 类型推导 C++98有一套单一的类型推导的规则用来推导函数模板.C++11轻微的修改了这些规则并且增加了两个推导规则,一个用于auto,一个用于decltype.接着C++14扩展了auto和decltype可以使用的语境.类型推导的普遍应用将程序员从必须拼写那些显然多余的类型中解放了出来,它

[C++11] Effective Modern C++ 读书笔记

本文记录了我读Effective Modern C++时自己的一些理解和心得. item1:模板类型推导 1)reference属性不能通过传值参数传入模板函数.这就意味着如果模板函数需要一个reference类型的参数,必须在模板声明中将其声明为reference,否则,即使使用一个reference类型的变量调用模板函数,类型推导的结果将不带reference属性. 2)constant和volatile属性也不能通过传值参数传入模板函数,但是可以通过reference参数传入这些属性. 3

effective modern C++读书笔记

类型推导: 1.ParamType是reference或pointer,不是universal reference 有引用则忽略引用,其余部分匹配T template <typenmae T> void f(T& param); int x = 27; const int cx =x; oonst int& rx = x; f(x);//T is int, paramtype is int& f(cx);//T is const int, paramtype is co

[.NET] 《Effective C#》读书笔记(二)- .NET 资源托管

<Effective C#>读书笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内存,我们并不需要去担心内存泄漏,资源分配和指针初始化等问题.不过,它也并非万能,因为非托管资源需要我们自己进行清理,如文件句柄.数据库连接.GDI+ 对象和COM 对象等. 目录 十二.推荐使用成员初始化器而不是赋值语句 十三.正确地初始化静态成员变量 十四.尽量减少重复的初始化逻辑 十五.使用 using

《Effective C++》 读书笔记之三 资源管理

<Effective C++> 读书笔记之三 资源管理 准备知识: 所谓资源就是,一旦用了它,将来必须还给系统.最常用的资源是动态分配内存,其他常见的资源有文件描述器.互斥锁.图形界面的字形和笔刷.数据库连接以及网络sockets. auto_ptr 是个"类指针对象",就是所谓的智能指针,其析构函数自动对其所指对象调用delete.auto_ptr位于 #include <memory> 头文件.由于auto_ptr被销毁时会自动删除它所指之物,所以一定要注意

《Effective C++》 读书笔记之四 设计与申明

<Effective C++> 读书笔记之四 设计与申明 条款18:让接口容易被正确使用,不易被误用. 重点: 好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. "促进正确使用"的办法包括接口的一致性,以及与内置类型的行为兼容. "阻止误用"的办法包括建立新类型.限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. tr1::shared_ptr支持定制型删除器.这可防范DLL问题,可被用来自动解除互斥锁等等. 20

《Effective Modern C++》翻译--条款2: 理解auto自动类型推导

条款2: 理解auto自动类型推导 如果你已经读过条款1关于模板类型推导的内容,那么你几乎已经知道了关于auto类型推导的全部.至于为什么auto类型推导就是模板类型推导只有一个地方感到好奇.那是什么呢?即模板类型推导包括了模板.函数和参数,而auto类型推断不用与这些打交道. 这当然是真的,但是没关系.模板类型推导和auto自动类型推导是直接匹配的.从字面上看,就是从一个算法转换到另一个算法而已. 在条款1中,阐述模板类型推导采用的是常规的函数模板: template<typename T>

[Effective Modern C++(11&amp;14)]Chapter 2: auto

1.更多的使用auto而不是显式类型声明 将大段声明缩减成auto 例如: typename std::iterator_traits<It>::value_type currValue = *b; auto currValue = *b; 使用auto可以防止变量未初始化 例如: int x1; //正确,但是未初始化 auto x2; //错误,没有初始化 auto x3 = 3; //正确,声明并初始化 在模板函数中可以使用auto来完成变量的自动类型推导 例如: template<