1.1 auto与模板类型推导

  1. 除了一个奇怪的例外,auto类型推导就是模板类型推导。
  2. 当使用 auto 声明变量时, auto 相当于模板中的 T,而变量的类型说明符充当 ParamType。
template<typename T>
void f(ParamType param);
f(expr); // 使用一些表达式来当做调用f的参数

编译器的行为就好像为每个声明都提供了:一个模板以及相应的初始化表达式。

auto x = 27;
const auto cx = x;
const auto& rx = x;

template<typename T> 		// 推导x类型的概念上的模板
void func_for_x(T param); 	 

func_for_x(27); 		// 概念上的调用:param的类型就是x的类型

template<typename T>
void func_for_cx(const T param); 	// 推导cx的概念上的模板

func_for_cx(x); 			// 概念调用:param的推导类型就是cx的类型

template<typename T>
void func_for_rx(const T& param); 	// 推导rx概念上的模板

func_for_rx(x); 			// 概念调用:param的推导类型就是rx的类型

1.2 auto 声明变量的三种情况

条款1根据ParamType的特征,把模板类型推导分为三种情况。在 auto 声明的变量上,类型声明代替了 ParamType 的作用,所以也有三种情况:

  1. 情况1:类型声明是指针或者引用,但不是通用的引用。
  2. 情况2:类型声明是通用引用。
  3. 情况3:类型声明既不是指针也不是引用。
auto x = 27; // 情况3(x既不是指针也不是引用)
const auto cx = x; // 情况3(cx二者都不是)
const auto& rx = x; // 情况1(rx是一个非通用的引用)
//情况2
auto&& uref1 = x; // x是int并且是左值,所以uref1的类型是int&
auto&& uref2 = cx; // cx是int并且是左值,所以uref2的类型是const int&
auto&& uref3 = 27; // 27是int并且是右值,所以uref3的类型是int&&
//数组和函数名称如何退化成指针
const char name[] = "R. N. Briggs"; // name的类型是const char[13]
auto arr1 = name; // arr1的类型是const char*
auto& arr2 = name; // arr2的类型是const char (&)[13]
void someFunc(int, double); // someFunc是一个函数,类型是 void (*)(int, double)
auto& func2 = someFunc; // func2的类型是 void (&)(int, double)

1.3 auto和模板类型推导不同之处

以下八种写法,都能编译通过:但并不完全相同。

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

std::intializer_list 是一个模板 ,这就意味着实例化时, T 的类型必须被推导出来:

auto x5 = { 1, 2, 3.0 }; // 错误! 不能将auto推导成std::intializer_list<T>

处理带括号的初始化表达式是auto类型推导和模板类型推导之间唯一的不同之处。

auto x = { 11, 23, 9 }; 	// x的类型是 std::initializer_list<int>

template<typename T> 		// 和x的声明等价的模板
void f(T param); 	
	 
f({ 11, 23, 9 }); 		// 错误!没办法推导T的类型

template<typename T>
void f(std::initializer_list<T> initList);

f({ 11, 23, 9 }); // T被推导成int,initList的类型是std::initializer_list<int>

//auto 和模板类型推导的本质区别就是 auto 假设花括号初始化代表的是std::initializer_list,但模板类型推导不是

C++14允许 auto 推导的函数返回类型,而且C++14的lambda可能会在参数声明里使用 auto 。但是,使用的是模板的类型推导,而不是 auto 的类型推导。

auto createInitList(){
    return { 1, 2, 3 }; // 错误: 无法推导出{ 1, 2, 3 }的类型
}
std::vector<int> v;auto resetV = [&v](const auto& newValue) { v = newValue; }; // C++14resetV({ 1, 2, 3 }); // 错误! 无法推导出{ 1, 2, 3 }的类型

1.4 要点速记

  1. auto类型推导通常与模板类型推导相同,但auto类型推导假定带花括号的初始化列表的类型表示为 std::initializer_list,而模板类型推导则不会这样假设。
  2. 在函数返回类型或 lambda 参数中使用 auto 意味着模板类型推导,而不是auto类型推导。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐