C++活到老学到老 auto
起因
2020年了,C++20似乎已经正式发布了,主流编译器应该都支持了吧。从C++11开始,每三年都会正式发布一版更新的标准,并伴随着各种新特性和标准库。变化太快有时候跟不上,是时候再回顾一下C++了,这东西活到老学到老啊。
这篇博文是受这个mediu文章启发,自己测试并总结出来的。主要对auto
关键字和相似的类型推断行为进行了探索。
经过
测试系统
Ubuntu 20.04, g++ 9.3.0。
源码在这里。
定义变量时的类型推断
相信自从C++11之后,大家都获得了这个利器,auto
。我们可以写
auto a = 0;
之前用一直没有仔细测试,对于一些litertal, auto
自动推断类型的方式和我们预想的是一致的,例如
auto a = 0; // int.
auto b = 0.0; // double.
auto c = 0.0f; // float.
auto d = "abc"; // const char*.#include <string>
using namespace std::string_literals;
auto e = "abc"s; // std::__cxx11::basic_string<char>.
注意如果想使用string literal输入给auto
进行对std::string
的推断,需要显式using namespace std::string_literals
.
当auto
和逗号表达式结合进行变量定义时,行为是这样的
auto a = 0, b = 1; // int, int.
auto c = 0, d = 1.0; // This is an error.
也就是说不能在逗号表达式内利用类型不一致的literal初始化不同的变量。
有趣的是用auto
对序列进行初始化。auto
似乎不能显式用在像vector
一类的对象的初始化上,但是可以忽略模板参数让编译器推断类型,有点和使用auto
类似,就放在一起了。
auto a = { 0, 1, 2 }; // std::initializer_list<int>.
auto a { 0, 1, 2 }; // This is an error.
auto a = { 0, 1.0, 2 }; // This is an error.
std::vector b { 0, 1, 2 }; // std::vector<int, std::allocator<int> >.
std::vector c = a; // std::vector<int, std::allocator<int> >.
std::array d { 0, 1, 2 }; // std::array<int, 2>.
std::pair e0 { 0, 1.0 }; // std::pair<int, double>.
auto e1 = std::make_pair( 0, 1.0 ); // std::pair<int, double>.
std::tuple f0 { 0, 1.0, 2.0f }; // std::tuple<int, double, float>.
auto f1 = std::make_tuple( 0, 1.0, 2.0f ); // std::tuple<int, double, float>.
std::tuple f2 = a; // std::tuple<std::initializer_list<int> >.
std::map g { std::pair{ 0, 1.0 }, std::pair{ 2, 3.0 } };// std::map<int, double, std::less<int>, std::allocator<std::pair<const int, double> > >.
注意,上述示例中 f2
的初始化并未得到一个可用的tuple。
带有引用的变量和structured binding
使用auto&
对变量进行定义是可以的。
auto a = 0; // int.
auto& b = a; // int&.
const auto& c = a; // const int&.
auto
关键字用在structured binding中,当配合引用符号&
使用时有奇效。
测试结果表明,使用implicit类型的pair或者tuple,或者使用std::make_pair()
和std::make_tuple()
无法传递reference。并且采用const auto&
或者auto&
进行的structured binding不能得到const
类型的变量。
使用explicit类型的pair或者tupole,可以传递引用,但是采用const auto
的structured binding仍然不能获得const
类型的变量(原始类型不是const
时)。
使用std::tie()
可以用const auto& []
实现对原始变量的引用,但是失去了const
。
测试下来const auto&
进行structured binding时,不能得到const
类型的引用(原始类型不是const
时)。
// Simple std::pair. Cannot bind to a reference.
std::pair a { 0, 1.0 };
auto [ a0, a1 ] = a; // int, double.
auto& [ a2, a3 ] = a; // int, double.
const auto& [a4, a5] = a; // int, double.
auto& [a6, a7] {a}; // int, dobule.// Simple std::tuple. Cannot bind to a reference.
std::tuple b { 0, 1.0, "2.0" }; // int, double, const char*.
auto [ b0, b1, b2 ] = b; // int, double, const char*.
auto& [ b3, b4, b5 ] = b; // int, double, const char*.// std::make_pair(). Cannot bind to a reference.
auto [c0, c1] = std::make_pair( 0, 1.0 ); // int, double.
const auto& [c2, c3] = std::make_pair( 0, 1.0 ); // int, double.auto d0 = 0, d1 = 1; // int, int.
const auto [d2, d3] = std::make_pair( d0, d1 ); // const int, const int.
auto [d4, d5] = std::make_pair<int&, int&>(d0, d1); // int, int.// std::make_tuple(). Cannot bind to a reference.
auto e0 = 0, e1 = 1; // int, int.
const auto [e2, e3] = std::make_tuple(e0, e1); // const int, const int.
const auto& [e4, e5] = std::make_tuple(e0, e1); // const int, const int.
const auto [e6, e7] = std::make_tuple<int&, int&>(e0, e1); // const int, const int.// Explicit std::pair and std::tuple can transfer reference.
std::pair<int&, int&> fp { e0, e1 }; // int&, int&.
const auto [fp0, fp1] = fp; // int&, int&. fp0 can be assigned to a new value and affect e0.std::tuple<int&, int&> ft { e0, e1 }; // int&, int&.
const auto [ft0, ft1] = ft; // int&, int&. ft0 can be assigned to a new value and affect e0.// Variables binded with auto are copies.
// Variables binded with auto& are references.
std::pair<int, int> gp { e0, e1 }; // int, int.
auto [gp0, gp1] = gp; // int, int. Assigning to gp0 will NOT affect gp.first.
auto& [gp2, gp3] = gp; // int&, int&. Assigning to gp2 WILL affect gp.first.std::tuple<int, int> gt { e0, e1}; // int, int.
auto [gt0, gt1] = gt; // int, int. Assigning to gt0 will NOT affect get<0>(gt).
auto& [gt2, gt3] = gt; // int&, int&. Assigning to gt2 WILL affect get<0>(gt).// The original variables are const.
const int ec0 = 0, ec1 = 1;
std::pair<const int&, const int&> fpc { ec0, ec1 };
auto [ fpc0, fpc1 ] = fpc; // const int&, const int&.
auto& [ fpc2, fpc3 ] = fpc; // const int&, const int&.// std::tie() can transfer reference.
// Binding with const auto& will drop the constness.
int x = 0, y = 1; // int, int.
const auto& [x0, y0] = std::tie(x, y); // int&, int&. x0 can affect x.const int w = 0, z = 1; // const int, const int.
const auto& [w0, z0] = std::tie( w, z ); // const int&, const int&.
auto& [ w1, z1 ] = std::tie( w, z ); // This is an error.
auto
用作函数的参数类型和返回类型
下面这个函数模板貌似是不能像我写的c0和c1那样实例化的。
template < typename T0, typename T1, typename T2 >
T2 add_two_t3( const T0& t0, const T1& t1 ) {return t0 + t1;
}auto a = 0;
auto b = 1.0;
auto c0 = add_two_t3(a, b); // Error.
double c1 = add_two_t3(a, b); // Error.
auto c2 = add_two_t3<int, double, double>(a, b); // OK.
原因是编译器无法推断T2的类型。但是采用auto
关键字作为返回值类型,是没问题的。
template < typename T0, typename T1>
auto add_two_t( const T0& a, const T1& b ) {return a + b;
}auto a = 0;
auto b = 1.0;
auto c = add_two_t(a, b); // OK.
我们甚至可以写
auto add_two( const auto& a, const auto& b) {return a + b;
}
auto
适用于lambda函数
与普通函数的情况类似auto
可作为lambda函数的参数类型和返回类型。下面两个lambda函数的效果是一样的(function signature中不包含返回值,并且参数列表的类型有些许不同)。auto
还用于保存一个lambda函数,否则的话,很难描述一个lambda究竟是什么类型。
auto g = [](const auto& a, const auto& b) {return a + b;};
auto g1 = [](const auto& a, const auto& b) -> auto {return a + b;};
上面保存在g
或者g1
中的lambda函数,可以作为参数实例化函数模板或者传递给一个auto
类型的参数。
template < typename T0, typename T1, typename TF >
auto apply( const T0& x, const T1& y, const TF& f) {return f(x, y);
}auto apply_auto( const auto& x, const auto& y, const auto& f ) {return f(x, y);
}auto c = apply( 2.0, 3.0f, g );
auto c1 = apply_auto( 4, 5.0f, g1 );
结果
我打算继续探索C++,活到老学到老。
C++活到老学到老 auto相关推荐
- 活到老学到老之《终身学习》
您好,我是码农飞哥,感谢您阅读本文!今天周末,我们不聊技术,不写代码.看一本小书来给生活加点颜色,今天看的书是<终身学习>. <终身学习 >何书也? 你没看错我说的<终身 ...
- 活到老, 学到老, 做到老-----想念导师赵日华
感觉上研究生的进步和提高主要源自跟着导师干活. 赵老师是做硬件的, 那时候的硬件就是Z80微处理器, 赵老师对这个处理器每个技术细节的熟悉程度让人吃惊, 可以直接用机器码写程序, 对每条指令,每个时序 ...
- 前端笔试题整理:活到老学到老②
14.介绍下观察者模式和订阅-发布模式的区别,各自适用于什么场景? 答案:观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知: 观察者模式就好像 ...
- 基于Thinkphp5+phpQuery 网络爬虫抓取数据接口,统一输出接口数据api
TP5_Splider 一个基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api.适合正在学习Vue,AngularJs框架学习 开发demo,需要接口并保证接口不跨 ...
- Free Code Camp 练习总结 —— JavaScript 基本知识
我会每天都更新我写东西,学大概有一段时间了,我感触还是挺大的,把之前基础知识又复习一遍,活到老学到老.希望能给在FreecodeCamp有同学有帮助,我会每天更新我在写FreecodeCamp,代码. ...
- iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案
前言 全面屏刚出时,网上有说反人类.但过去这么久了,趋于技术的进步或看久了,大家也都慢慢习惯了(只是笔者还是买不起全面屏).官方适配中文版文档也出来了. 图源:( baijiahao.baidu.co ...
- 向大牛学习!11名顶尖设计师的设计启迪+职业忠告
@十萬個為什麽 :优秀的设计师活到老学到老.在Springboard,我们把用户体验和数据科学方面的导师与学员相互组队,这对于聆听前辈的建议有重大意义.我们整合了许多顶尖从业者的建议,用来编写我们的用 ...
- 前端Vue学习之路(一)-初识Vue
Vue学习之路 (一) 1.引言 2.更换npm国内镜像源 3.用npm下载Vue 4.Vue全家桶 5.使用命令创建项目 5.推荐插件 6.推荐网站 7.学习扩展 1.引言 先安装node.js环境 ...
- 全网最全最详细的Windows下安装Anaconda2 / Anaconda3(图文详解)
不多说,直接上干货! 说明: Anaconda2-5.0.0-Windows-x86_64.exe安装下来,默认的Python2.7 Anaconda3-4.2.0-Windows-x86_64.ex ...
最新文章
- 利用WxJava实现PC网站集成微信登录功能,核心代码竟然不超过10行
- StatQuest-对RNA-seq的介绍
- apache+svn服务搭建
- JAVA Thread线程异常监控
- MVC模式和文档/视图结构
- 《IBM-PC汇编语言程序设计》(第2版)【沈美明 温冬婵】——第五章——自编解析与答案
- 【华为云 ModelArts-Lab AI实战营】第三期:图像分类 (III) 模型参数网络调优
- 零基础 Amazon Web Services (AWS) 入门教程 (列表)
- GDB调试乱序,出现value optimized out解决方法
- python处理csv文件将id相同的行合并到同一行并用符号将其隔开_Python探索性数据分析,这样才容易掌握...
- 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析
- 关于SqlServer导入access数据库,十进制字段的精度过小的问题
- UG二次开发GRIP显示图层
- YYH的王国(NOIP模拟赛Round 6)
- 软件测试题目 如何测一个三角形,软件测试三角形问题(覆盖测试)
- N-gram 语言模型
- css 超出显示省略号
- NetBackup 8.2 LinuxR Oracle脚本备份
- android inactive InputConnection
- 【机器学习】如何理解vias和bias?
热门文章
- 10岁男童高考566分8岁开发操作系统
- 你需要了解的opn模块
- You have not agreed to the Xcode license agreements. You must agree to both license agreements below
- 设计中的确定性与不确定性思考
- 在线运行 Linux,真滴牛逼。
- 软件架构-Nosql之redis
- 【报错及解决】Variable w already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally
- python音标是什么_python转换工具之汉语拼音与国际音标的实现
- echart 时间滚动_echarts x,y轴数据太长自动滚动(每次只显示固定数量,定时滚动显示其它)...
- 上海发布通知:年底前全面清退不符条件的网约车车辆和驾驶员