起因

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相关推荐

  1. 活到老学到老之《终身学习》

    您好,我是码农飞哥,感谢您阅读本文!今天周末,我们不聊技术,不写代码.看一本小书来给生活加点颜色,今天看的书是<终身学习>. <终身学习 >何书也? 你没看错我说的<终身 ...

  2. 活到老, 学到老, 做到老-----想念导师赵日华

    感觉上研究生的进步和提高主要源自跟着导师干活. 赵老师是做硬件的, 那时候的硬件就是Z80微处理器, 赵老师对这个处理器每个技术细节的熟悉程度让人吃惊, 可以直接用机器码写程序, 对每条指令,每个时序 ...

  3. 前端笔试题整理:活到老学到老②

    14.介绍下观察者模式和订阅-发布模式的区别,各自适用于什么场景? 答案:观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知: 观察者模式就好像 ...

  4. 基于Thinkphp5+phpQuery 网络爬虫抓取数据接口,统一输出接口数据api

    TP5_Splider 一个基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api.适合正在学习Vue,AngularJs框架学习 开发demo,需要接口并保证接口不跨 ...

  5. Free Code Camp 练习总结 —— JavaScript 基本知识

    我会每天都更新我写东西,学大概有一段时间了,我感触还是挺大的,把之前基础知识又复习一遍,活到老学到老.希望能给在FreecodeCamp有同学有帮助,我会每天更新我在写FreecodeCamp,代码. ...

  6. iOS 关于全面屏适配的方案及UI在不同尺寸下适配方案

    前言 全面屏刚出时,网上有说反人类.但过去这么久了,趋于技术的进步或看久了,大家也都慢慢习惯了(只是笔者还是买不起全面屏).官方适配中文版文档也出来了. 图源:( baijiahao.baidu.co ...

  7. 向大牛学习!11名顶尖设计师的设计启迪+职业忠告

    @十萬個為什麽 :优秀的设计师活到老学到老.在Springboard,我们把用户体验和数据科学方面的导师与学员相互组队,这对于聆听前辈的建议有重大意义.我们整合了许多顶尖从业者的建议,用来编写我们的用 ...

  8. 前端Vue学习之路(一)-初识Vue

    Vue学习之路 (一) 1.引言 2.更换npm国内镜像源 3.用npm下载Vue 4.Vue全家桶 5.使用命令创建项目 5.推荐插件 6.推荐网站 7.学习扩展 1.引言 先安装node.js环境 ...

  9. 全网最全最详细的Windows下安装Anaconda2 / Anaconda3(图文详解)

    不多说,直接上干货! 说明: Anaconda2-5.0.0-Windows-x86_64.exe安装下来,默认的Python2.7 Anaconda3-4.2.0-Windows-x86_64.ex ...

最新文章

  1. 利用WxJava实现PC网站集成微信登录功能,核心代码竟然不超过10行
  2. StatQuest-对RNA-seq的介绍
  3. apache+svn服务搭建
  4. JAVA Thread线程异常监控
  5. MVC模式和文档/视图结构
  6. 《IBM-PC汇编语言程序设计》(第2版)【沈美明 温冬婵】——第五章——自编解析与答案
  7. 【华为云 ModelArts-Lab AI实战营】第三期:图像分类 (III) 模型参数网络调优
  8. 零基础 Amazon Web Services (AWS) 入门教程 (列表)
  9. GDB调试乱序,出现value optimized out解决方法
  10. python处理csv文件将id相同的行合并到同一行并用符号将其隔开_Python探索性数据分析,这样才容易掌握...
  11. 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析
  12. 关于SqlServer导入access数据库,十进制字段的精度过小的问题
  13. UG二次开发GRIP显示图层
  14. YYH的王国(NOIP模拟赛Round 6)
  15. 软件测试题目 如何测一个三角形,软件测试三角形问题(覆盖测试)
  16. N-gram 语言模型
  17. css 超出显示省略号
  18. NetBackup 8.2 LinuxR Oracle脚本备份
  19. android inactive InputConnection
  20. 【机器学习】如何理解vias和bias?

热门文章

  1. 10岁男童高考566分8岁开发操作系统
  2. 你需要了解的opn模块
  3. You have not agreed to the Xcode license agreements. You must agree to both license agreements below
  4. 设计中的确定性与不确定性思考
  5. 在线运行 Linux,真滴牛逼。
  6. 软件架构-Nosql之redis
  7. 【报错及解决】Variable w already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally
  8. python音标是什么_python转换工具之汉语拼音与国际音标的实现
  9. echart 时间滚动_echarts x,y轴数据太长自动滚动(每次只显示固定数量,定时滚动显示其它)...
  10. 上海发布通知:年底前全面清退不符条件的网约车车辆和驾驶员