码迷,mamicode.com
首页 > 编程语言 > 详细

c++11-17 模板核心知识(六)—— 理解auto推导规则

时间:2020-11-25 12:09:31      阅读:7      评论:0      收藏:0      [点我收藏+]

标签:类型推导   const   form   区别   推导   error   int   list()   src   

上篇文章讲了模板参数的推导规则,其实auto的推导规则跟模板参数的推导基本上一样的,都是推导参数嘛。比如上篇文章的模板基本结构是:

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

......
f(expr);

编译器使用expr来推断ParamTypeT

那么对应在auto推导中,auto就对应了T,变量的type specifier就是ParamType

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

这里,cx的type specifier就是const auto,rx的type specifier就是const auto&.

我们可以想象成在推导auto类型时,编译器就是在做一次模板参数类型推断:

  • 推断x :
template<typename T>
void func_for_x(T param);

func_for_x(27);
  • 推断cx :
template<typename T>
void func_for_cx(const T param);

func_for_cx(x);
  • 推断rx :
template<typename T>
void func_for_rx(const T& param);

func_for_rx(x);

在模板参数推导中,我们根据ParamType将情况分成了三类。在auto推导中,我们同样可以根据type specifier来分成三种情况:

  • type specifier是一个指针或者引用,但不是universal reference(或者叫forwarding references).
  • type specifier是一个universal reference。
  • type specifier既不是指针也不是引用。

技术图片

Case 1 : type specifier是一个指针或者引用,但不是universal reference

const auto& rx = x;     

上面分析过,不再赘述。

技术图片

Case 2 : type specifier是一个universal reference

auto&& uref1 = x;         // x is int and lvalue, so uref1‘s type is int&
auto&& uref2 = cx;      // cx is const int and lvalue, so uref2‘s type is const int&
auto&& uref3 = 27;     // 27 is int and rvalue, so uref3‘s type is int&&

技术图片

Case 3 : type specifier既不是指针也不是引用

auto x = 27;
const auto cx = x;

技术图片

注意这个Case的情况,假如我们有个函数返回引用,我们使用auto接收返回值,如果我们想改变函数的返回值,那么必须用auto&,而不是auto,因为这里和函数模板参数推断规则一样,是pass-by-value,会忽略引用、const和volatile:

int x = 50;

int &f() { return x; }

int main() {

  auto a1 = f();
  a1 = 10;        // x = 50

  auto &a2 = f();
  a2 = 20;      // x = 20

  return 0;
}

数组和函数类型推断

在函数模板参数推断中讨论了数组和函数作为模板参数的推断情况,在auto类型推断中情况也是相同的:

const char name[] = "R. N. Briggs";

auto arr1 = name;            // arr1‘s type is const char*
auto& arr2 = name;        // arr2‘s type is const char (&)[13]
void someFunc(int, double);

auto func1 = someFunc;              // func1‘s type is void (*)(int, double)
auto& func2 = someFunc;           // func2‘s type is void (&)(int, double)

auto与函数模板参数推断的区别

从C++11起有4种选择可以定义一个整形变量:

auto x1 = 27;
auto x2(27);
auto x3 = { 27 };
auto x4{ 27 };

最后两种是C++11的新特性:统一初始化(uniform initialization),就是这个造成了模板参数推导和auto类型推导的最大区别 :

auto x1 = 27;                 // type is int, value is 27
auto x2(27);                 // type is int, value is 27

auto x3 = { 27 };           // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 };               // type is std::initializer_list<int>, value is { 27 }

特殊点在于:如果使用uniform initialization来进行auto类型推断,那么最终auto推断出的结果是std::initializer_list<int>

所以下面的代码会编译报错:

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

f({11, 23, 9});

但是如果指定ParamTypestd::initializer_list<T>,则可以正确的推断T的类型:

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

f({ 11, 23, 9 });        // T deduced as int, and initList‘s type is std::initializer_list<int>

C++14中更特殊的情况

在C++14中,允许将函数返回值和lambda参数声明为auto,但是在这种情况下,auto的类型推断使用的是模板参数类型推断规则:

auto createInitList() {
  return { 1, 2, 3 };             // error: can‘t deduce type for { 1, 2, 3 }
}
std::vector<int> v;

…
auto resetV = [&v](const auto& newValue) { v = newValue; };           // C++14

…
resetV({ 1, 2, 3 }); // error! can‘t deduce type  for { 1, 2, 3 }

(完)

朋友们可以关注下我的公众号,获得最及时的更新:

技术图片

c++11-17 模板核心知识(六)—— 理解auto推导规则

标签:类型推导   const   form   区别   推导   error   int   list()   src   

原文地址:https://www.cnblogs.com/zhangyachen/p/14013607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!