第2课 auto类型推导(1)

一、auto类型推导

(一)与模板类型推导映射关系

1、auto类型推导与模板类型推导可以建立一一映射关系,它们之间存在双向的算法变换。auto扮演模板中T的角色,而变量的类型及修饰词(如const或引用)扮演ParamType的角色

2、举例说明两者映射关系:(auto相当于T)

     (1)与auto x = 27等价的函数模板

template<typename T>

void func_x(T param); //T ←→ auto,即auto x 相当于这里的T param

func_x();

(2)与const auto cx = x等价的函数模板

template<typename T>

void func_x(const T param); // const auto ←→ const T

func_cx(x);

(3)与const auto& rx = x;等价的函数模板

template<typename T>

void func_crx(const T& param); // const auto&←→const T&

func_crx(x);

(二)auto类型推导规则(与函数模板推导规则基本一致)

1、推导规则:

①规则1:auto& x或auto* x,即指针或引用时。(与函数模板推导规则1类似)

②规则2:auto&& x,即万能引用时。(与函数模板推导规则2类似)

③规则3:auto x,即按值推导(非指针也非引用,与函数模板推导规则3类似)

2、注意事项:

①auto声明的变量必须马上初始化,以让编译器推断出它的实际类型。

②与函数模板推导类似,auto x总是推导出值类型auto&&总是推导出引用类型(可能左值引用,也可能是右值引用)。

③auto不能用于函数形参(但可用于lambda表达式形参的自动推导)

【编程实验】auto类型推导

#include <iostream>
#include <boost/type_index.hpp> using namespace std;
using boost::typeindex::type_id_with_cvr; //辅助类模板,用于打印T的类型
template <typename T>
void printType(string s)
{
cout <<s <<" = "<< type_id_with_cvr<T>().pretty_name() << endl;
} //测试函数
void myfunc(int, double)
{
} int main()
{
//规则3:按值推导,如auto x
auto x = ;
const auto cx = x;
int& a = x;
auto ra = a; //由于按值推导,a的引用会被忽略,故ra = int printType<decltype(cx)>("cx"); //cx = const int
printType<decltype(ra)>("ra"); //ra = int //规则1:auto引用或指针(auto&和auto*)
const auto& rx = x; //auto=int, rx=const int&
const auto* const px = &x; //auto=int, px=const int* const;
const volatile auto cvx = x; //cvx = const volatile int;
auto* cpx = px; //cpx = const int* (注意:只保留px的底层const,而顶层const被舍弃!) printType<decltype(rx)>("rx"); //rx = const int&
printType<decltype(px)>("px"); //px=const int* const;
printType<decltype(cvx)>("cvx"); //cvx=const volatile int;
printType<decltype(cpx)>("cpx"); //cvx=const int*; //规则2:auto&&万能引用
auto&& uref1 = x; //用左值初始化,返回左值引用。auto=int&,x=int&
auto&& uref2 = cx;//用左值初始化,返回左值引用。由于是引用,会传为cv属性,即auto=const int&, uref2=const int&
auto&& uref3 = ;//用右值初始化,返回右值引用。即auto=int, uref3=int&&
auto&& uref4 = px;//用左值初始化,返回左值引用,由于引用表示变量本身,所以uref4=const int* const&。(顶层与底层const均保留) printType<decltype(uref1)>("uref1"); //uref1 = int&
printType<decltype(uref2)>("uref2"); //uref2 = const int&
printType<decltype(uref3)>("uref3"); //uref3 = int&&
printType<decltype(uref4)>("uref4"); //uref4 = const int* const & //数组或函数名类型的推导
const char name[] = "SantaClaus";
auto arr1 = name; //退化为数组指针: arr1 = const char*
auto& arr2 = name;//数组引用: arr2 = const char(&)[11] printType<decltype(arr1)>("arr1"); //arr1 = const char*
printType<decltype(arr2)>("arr2"); //arr2 = const char(&)[11] auto func1 = myfunc; //退化为函数指针:func1 = void(*)(int,double)
auto& func2 = myfunc;//数组引用:func2 = void(&)(int,double) printType<decltype(func1)>("func1"); //arr1 = const char*
printType<decltype(func2)>("func2"); //arr2 = const char(&)[11] // //new中使用auto
auto ax = new auto();
printType<decltype(ax)>("ax"); //ax = int return ;
}
/*输出结果:
cx = int const
ra = int
rx = int const &
px = int const * const
cvx = int const volatile
cpx = int const *
uref1 = int &
uref2 = int const &
uref3 = int &&
uref4 = int const * const &
arr1 = char const *
arr2 = char const (&)[11]
func1 = void (__cdecl*)(int,double)
func2 = void (__cdecl&)(int,double)
ax = int *
*/

二、auto推导的特殊规则

(一)auto声明的变量使用大括号初始化表达式进行初始化时,推导出的类型是initializer_list<T>类型。注意:采用“={}”初始化的才是initializer_list<T>类型,如果声明时直接在变量后面加{}的(如auto x{14},x为int类型,这里只能有一个元素,多了则编译不过!),则不是initializer_list<T>类型。

(二)C++14中,auto用于推导函数的返回值或lambda形参时,使用的是模板类型的推导,而不是auto类型的推导。需要特别注意的是,与auto推导最大的不同在于模板类型推导时不会将{}初始化表达式推导为initializer_list<T>类型,而auto推导会!注意,这两者的区别!(见下面《编程实验》)

【编程实验】auto类型推导的特殊规则

#include <iostream>
#include <vector>
#include <boost/type_index.hpp> using namespace std;
using boost::typeindex::type_id_with_cvr; //辅助类模板,用于打印T的类型
template <typename T>
void printType(string s)
{
cout << s << " = " << type_id_with_cvr<T>().pretty_name() << endl;
} template<typename T>
//void func(initializer_list<T> param)
void func(T param)
{
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl;
cout << "param = " << type_id_with_cvr<decltype(param)>().pretty_name() << endl;
} //C++14允许auto用于推导函数的返回值
auto func_i()
{
return ; //采用模板类型推导,这里与auto的类型推导结果是一样的,返回值为int型。
} //auto createInitList()
//{
// //return { 1, 2, 3 }; //编译不通过!auto在返回值类型推导上采用的是模板类型推导。(见下面分析)
//} template<typename T>
auto createInitList() ->initializer_list<T>
{
return { , , }; //由于auto在返回值类型是采用模板类型而不是auto类型的来推导。
//而模板类推导时,不会将大括号推导为initializer_list,即return中从语句中的{}(是个
//initialize_list<int>类型)到auto采用的是模板类型推导,与func({1,2,3})类似,从这里
//推出这个是initializer_list<T>类型,所以必须在尾随的返回值表达式中要手动加
//上->initializer_list<T>
} int main()
{
auto x1 = ; //C++98语法: 类型为int
auto x2(); //同上 auto x3 = { }; //C++11语法:x3为initializer_list<int> <== 当auto遇到“={}”时(即(大括号赋值初始化)。
auto x4 {}; //C++11语法,类型为int,注意这种方式初始化为int,并且只能有一个元素。注意与x3的区别! printType<decltype(x1)>("x1");
printType<decltype(x2)>("x2");
printType<decltype(x3)>("x3");
printType<decltype(x4)>("x4"); //auto类型推导的特殊规则:可以将{}推导为initializer_list<T>类型。
auto x = { , , }; //x: initializer_list<int>类型,共有3个元素。
printType<decltype(x)>("x"); //模板类型推导时,无法将{}推导为initializer_list<T>类型
//func({ 8, 9, 10 }); //错误,此处的实参为initializer<int>类型,由于模板类型推导时无法将
//{8, 9, 10}推导为initializer_list<T>,编译失败。
//如果将形参改为intializer_list<T>,将可以编译成功! auto func_ret = createInitList<int>(); //func_ret = class std::initializer_list<int>
printType<decltype(func_ret)>("func_ret"); auto fi = func_i(); //fi = int
printType<decltype(fi)>("func_i"); //在lambda表达式形参中用auto声明的变量也不会将{}推导为initializer_list<T>类型。
std::vector<int> v = {, , , };
auto resetV = [&v](const auto& newValue) { //auto resetV = [&v](const initializer_list<int>& newValue) { v = newValue;
}; //resetV({ 5, 6, 7}); //lambda形参中的auto也是采用模板类型推导,因此推导时{}不会被自动推导为initializer_list<T> return ;
}
/*输出结果:
x1 = int
x2 = int
x3 = class std::initializer_list<int>
x4 = int
x = class std::initializer_list<int>
func_ret = class std::initializer_list<int>
func_i = int
*/

第2课 auto类型推导(1)的更多相关文章

  1. 第3课 auto类型推导(2)

    第3课 auto类型推导(2) 一.使用auto的优势 (一)避免使用未初始化变量 (二)可简化变量/对象类型的声明 (三) 在某些场合无法判断出类型时,可用auto自动推导(如lambda表达式) ...

  2. 第4课 decltype类型推导

    第4课 decltype类型推导 一.decltype类型推导 (一)语法: 1.语法:decltype(expr),其中的expr为变量(实体)或表达式 2.说明: ①decltype用于获取变量的 ...

  3. Effective Modern C++翻译(3)-条款2:明白auto类型推导

    条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...

  4. auto类型推导

    引言 auto : 类型推导. 在使用c++的时候会经常使用, 就像在考虑STL时迭代器类型, 写模板的时候使用auto能少写代码, 也能帮助我们避免一些隐患的细节. auto初始化 使用auto型别 ...

  5. 类型推导:函数模板与auto

    1.从函数模板谈起 函数模板的类型推导机制是在c++98时代就有的,auto的类型推导机制与其基本一致,所以先理解函数模板类型推导. 函数模板可以用如下代码框架表示: #template<typ ...

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

    条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇 ...

  7. item 2: 理解auto类型的推导

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果你已经读过item 1的模板类型推导,你已经知道大部分关于au ...

  8. c++11——auto,decltype类型推导

    c++11中引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能够方便的获取复杂的类型,而且还能简化书写,提高编码效率.     auto和decltype的类型推导都是编译器在 ...

  9. 模板类型推导、auto推导

    effective modern c++ 果然是神书,干货满满,简单记录下. item1 模板推倒 典型的模板函数 temlate<class T> void fn(ParamType p ...

随机推荐

  1. python正确使用异常处理机制

    一.不要过度使用异常 不可否认,Python 的异常机制确实方便,但滥用异常机制也会带来一些负面影响.过度使用异常主要表现在两个方面: 把异常和普通错误混淆在一起,不再编写任何错误处理代码,而是以简单 ...

  2. Ubuntu Nginx https 配置

    #配置http跳转到https 80跳转443server { listen ; server_name www.***.com www.***.cn; https://$server_name$re ...

  3. C语言语法教程-结构体

    2018-09-30 结构体中成员变量地址是连续的,结构体用于描述记录. Create a struct //---------------------------- //struct1.c //创建 ...

  4. IDEA 部署spring Cloud

    Spring cloud Eureka Eureka Server,注册中心 Eureka Client,所有要进行注册的微服务通过Eureka Client 连接到 Eureka Server ,完 ...

  5. 初识Markdown

    目录 一.基础语法 二.语法规则 1.标题 2.列表 3.文字格式 4.链接 5.图片 6.引用 7.水平分隔线 8.代码块 9.表格 10.文档目录 11.转义定义 写在前面 Markdown(简称 ...

  6. angularJS 在edge浏览器上传文件,无法主动触发ng-click

    今天发现的问题 在谷歌浏览器一直运行良好的功能,在edge浏览器不能使用. 代码参考我的另一篇博客:WebAPI Angularjs 上传文件 不能运行的原因 下图红框中的代码在edge浏览器中无法执 ...

  7. python——CSV转Excel

    在转换之前,事先需要将csv文件另存为此格式 import pandas as pd def csv_to_xlsx_pd(): csv = pd.read_csv(r'C:\Users\Jery\D ...

  8. ES6 Promise对象(七)

    一.Promise介绍1.Promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果2.Promise可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函 ...

  9. mysql数据库之主从复制+双主--MMM

    mysql复制:在主数据库中,前端用户每执行一个写操作/语句,都会在二进制日志中保存一个事件,把这个事件从mysql的服务器中3306端口发送给从服务器,从服务器把这个事件接受下来,接受下来先保存在本 ...

  10. flask的客户端服务端

    1.首先要进行后端与前端的连接有get 和post请求 get请求是直接在网页上打出已将定义好的网址 if __name__ == '__main__': app.run(host="loc ...