ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

《Effective Modern C++》学习笔记 - Item 2: 理解auto类型推导

2021-12-15 13:00:52  阅读:182  来源: 互联网

标签:27 Effective 推导 int auto Modern 类型 模板


  • 除了一种特殊情况外,auto 类型推导就是模板类型推导(尽管二者在形式上看起来不同)
  • 当变量用 auto 声明时, auto 取代了模板中 T 的角色,而变量的类型等同于 ParamType。下面的例子展示了二者的等价性:
auto x = 27; 			// 等价于以下模板推导
template<typename T> 	// 推导x类型的假想模板,下同
void func_for_x(T param); 
func_for_x(27); 

const auto cx = x;		// 等价于以下模板推导
template<typename T>
void func_for_cx(const T param);
func_for_cx(x);

const auto& rx = x;		// 等价于以下模板推导
template<typename T>
void func_for_rx(const T& param);
func_for_rx(x);
  • 类似于模板推导的三种情况:
    1. Case 1: 类型标识符(type specifier)是指针或引用,但不是万能引用。
    2. Case 2:类型标识符是万能引用。
    3. Case 3: 类型标识符既不是指针也不是引用
  • 上面的例子已经展示了Case 1和3,Case 2的运作方式也如预期:
auto&& uref1 = x;	// x是左值int,所以uref1是int&
auto&& uref2 = cx; 	// cx是左值const int,所以uref2是const int&
auto&& uref3 = 27;	// 27是右值int,所以uref3是int&&
  • 对数组和函数的讨论也对 auto 成立:
const char name[] = "hello";
auto  arr1 = name;	// arr1是const char*
auto& arr2 = name;	// arr2是const char (&)[13]

void someFunc(int, double);
auto  func1 = someFunc; // func1是void (*)(int, double)
auto& func2 = someFunc;	// func2是void (&)(int, double)
  • 二者只在一个方面不同。C++11引入了统一初始化(uniform initialization),以下四种初始化方式的结果是一样的:
// 都将x初始化为int值27
int x1 = 27;
int x2(27);
int x3 = { 27 };
int x4{ 27 };

但如果直接将标识符改为 auto,这些声明仍都能通过编译,但意思不同。前两个仍声明一个值为27的 int但后两个声明的是包含一个元素27的 std::initializer_list<int>

auto x1 = 27;		// 类型为int,值为27
auto x2(27);		// 同上
auto x3 = { 27 };	// 类型为std::initializer_list<int>, 值为 { 27 }
auto x4{ 27 };		// 同上

这是由于 auto 类型推导的一条特殊规则:当使用大括号包围的初始化器(initializer)对一个 auto 描述的变量进行初始化时,推导出的类型是 std::initializer_list。如果推导不出这样的类型(如大括号包围的初始化器中有多个不同类型的元素)时,代码会编译报错。

要理解这里其实是一个两步的推导过程:由于 x 使用 大括号初始化,首先要推导出 xstd::initializer_list<T>,而后者又是一个模板,所以要从初始化列表中推出 T 的类型。

以上适用于 auto 的规则并不适用于模板推导,例如以下代码会报错:

template<typename T>
void f(T param);

f({ 11, 23, 9 }); // error!

解决方法为:

template<typename T>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 });
  • C++14还允许使用 auto 推导函数返回值,以及在lambda函数中使用 auto 声明参数。然而 auto 的这些使用遵循的是模板类型推导的规则,而不是 auto 类型推导的规则,所以以下代码均会报错:
auto createInitList()
{
	return { 1, 2, 3 }; // error
}

std::vector<int> v;
auto resetV =
	[&v](const auto& newValue) { v = newValue; }; // C++14
resetV({ 1, 2, 3 }); 	// error

总结

  1. auto 类型推导通常与模板类型推导相同,但 auto 类型推导将大括号包裹的初始化器(initializer)识别为 std::initializer_list,而模板类型推导不会。
  2. auto 在函数返回值类型或lambda函数参数中遵循模板类型推导规则,而不是auto 类型推导的规则。

标签:27,Effective,推导,int,auto,Modern,类型,模板
来源: https://blog.csdn.net/Altair_alpha/article/details/121949230

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有