第2课 auto类型推导(1)
第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)的更多相关文章
- 第3课 auto类型推导(2)
第3课 auto类型推导(2) 一.使用auto的优势 (一)避免使用未初始化变量 (二)可简化变量/对象类型的声明 (三) 在某些场合无法判断出类型时,可用auto自动推导(如lambda表达式) ...
- 第4课 decltype类型推导
第4课 decltype类型推导 一.decltype类型推导 (一)语法: 1.语法:decltype(expr),其中的expr为变量(实体)或表达式 2.说明: ①decltype用于获取变量的 ...
- Effective Modern C++翻译(3)-条款2:明白auto类型推导
条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...
- auto类型推导
引言 auto : 类型推导. 在使用c++的时候会经常使用, 就像在考虑STL时迭代器类型, 写模板的时候使用auto能少写代码, 也能帮助我们避免一些隐患的细节. auto初始化 使用auto型别 ...
- 类型推导:函数模板与auto
1.从函数模板谈起 函数模板的类型推导机制是在c++98时代就有的,auto的类型推导机制与其基本一致,所以先理解函数模板类型推导. 函数模板可以用如下代码框架表示: #template<typ ...
- 《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导
条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇 ...
- item 2: 理解auto类型的推导
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果你已经读过item 1的模板类型推导,你已经知道大部分关于au ...
- c++11——auto,decltype类型推导
c++11中引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能够方便的获取复杂的类型,而且还能简化书写,提高编码效率. auto和decltype的类型推导都是编译器在 ...
- 模板类型推导、auto推导
effective modern c++ 果然是神书,干货满满,简单记录下. item1 模板推倒 典型的模板函数 temlate<class T> void fn(ParamType p ...
随机推荐
- 使用Ueditor上传图片到图片服务器(一)
网站的文章,通过运营平台来发布文章(图文消息),上传图片等.百度Ueditor比较成熟就采用了该技术,另外上传的图片是网站系统以及运营平台系统共享的,所以考虑搭建独立的图片服务器,以后也可以提供给公司 ...
- Dozer JAVA的POJO 映射工具
Dozerhttp://www.manongjc.com/article/50949.html JAVA的映射工具 BeanUtils dozer的使用方法https://blog.csdn.net/ ...
- 像修改本机代码一样修改远端服务器的PHP网站
映射vps目录到自己电脑的摸索记录 最近拿discuz做了一个网站,需要修改模板文件之类的,还需要调试微信和QQ登陆的接口.都是些位置零散的小修改,但是有些需要在线上才能调试(QQ微信的oauth登陆 ...
- ASP.NET Core 3.0 解决无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称错误
写在前面 在 ASP.NET Core 的项目中 使用 CodeFirst 的模式,进行初始化迁移时.出现如图所示的问题: 在度娘哪里查了半天之后,才从这个帖子里找到了答案.传送门 分析原因 ASP. ...
- Redis之缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
目录 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 1.缓存雪崩 2.缓存穿透 3.缓存预热 4.缓存更新 5.缓存降级 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 ...
- CentOS 7.0 使用yum 安装 Mariadb
第一步: 使用命令查看是否已经安装: mysql -u root -p 返回 Enter password: 时表示已经安装成功的,需要卸载安装. 第二步: 使用yum直接安装mariadb,注意带 ...
- 把JSON数据格式转换为Python的类对象
JOSN字符串转换为自定义类实例对象 有时候我们有这种需求就是把一个JSON字符串转换为一个具体的Python类的实例,比如你接收到这样一个JSON字符串如下: {"Name": ...
- 添加shiv让所有现代浏览器都支持 HTML5 语义元素 html5.js让IE(包括IE6)支持HTML5元素方法
引用Google的html5.js文件 <!--[if IE]> <script src=”http://html5shiv.googlecode.com/svn/trunk/htm ...
- 8、如何将本地新创建的项目上传到gitHub(gitLab)上
Git 常用命令 1. cd 项目目录 2.git init //变成git仓库 3.git add . //将项目添加到本地仓库 4.git commit -m '备注' //将项目提交 ...
- doucment的获取节点的信息
document.activeElement 返回当前获取焦点元素 document.addEventListener() 向文档添加句柄 document.adoptNode(node) 从另外一个 ...