1. 模板型别推导
  2. auto型别推导
  3. decltype

模板型别推导

template

void f(ParamType param);

f(expr)//从expr推导T和ParamType的型别

情形一:ParamType是哥指针或者引用,但不是万能引用

  • 若expr有引用型别,先将引用忽略
  • 随后对expr的型别和ParamType的型别进行模式匹配,决定T的型别

template

void<T& param>

型别 T的型别 param型别
int x=27 int int int&
const int cx=x const int const int const int&
const int &rx=x const int& const int const int&

template

void<const T& param>

型别 T的型别 param型别
int x=27 int int const int&
const int cx=x const int int const int&
const int &rx=x const int& int const int&

template

void<T* param>

型别 T的型别 param型别
int x=27 int int int*
const int*px=&x const int* const int const int*

情形二:ParamType是个万能引用

  • 若expr是个左值,则T和ParamType都会推导为左值引用,1、T推到为左值引用的唯一情形 2、右值引用的语法,推导结果确是左值引用(通用引用?)
  • expr是右值,则和情形一类似

template

void<T&& param>

型别 T的型别 param型别
int x=27 int int& int&
const int cx=x const int const int& const int&
const int& rx=x const int& const int& const int&
27 int int&&

情形三:ParamType既非指针也非引用

template

void f(T param)

  • expr有引用型别,忽略
  • expr是个const变量,忽略,expr是个volatile变量,忽略
型别 T的型别 param型别
int x=27 int int int
const int cx=x const int int int
const int &rx=x const int& int int

const char* const ptr=“hello world”

param型别推导为const char*

数组实参

1
2
3
4
5
6
7
8
9
10
const char name[12]="hello world"; //const char[13]
const char* ptrtoname=name; //数组退化为指针

template<typename T>
void f(T param);
f(name); //T为const char*

template<typename T>
void f(T& param);
f(name); //T为const char[13] param const char(&)[13]

函数实参

1
2
3
4
5
6
7
8
9
10
void someFunc(int ,double);

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

template<typename T>
void f2(T& param);

f1(someFunc); //para void(*)(int ,double)
f2(someFunc); //para void(&)(int ,double)

auto型别推导

(概念上等价)

同模板型型别推导

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
auto x=27;
//==
template<typename T>
void func_for_x(T param);

template<typename T>
void func_for_cx(const T param);

template<typename T>
void func_for_rx(const T& param);

anto x=27; //情形三 int
const auto cx = x; //情形三 const int
const anto& rx = x; //情形一 const int&

auto&& uref1 = x; //二,int&
auto&& uref2 = cx; //二,const int&
auto&& uref3 = 27; //二,auto&&

特殊情况也相同

1
2
3
4
5
6
7
const char name[]="Ganhy";
auto arr1=name; //const char*
auto& arr2=name; //const char(&)[6]

void func(int,double);
auto func1(func); //void(*)(int,double)
auto func2(func); //void(&)(int double)

不同指之处

c++11引入统一初始化 int x{27};==int x=27;

auto x1{27}; 型别推导为std::initializer_list,值是{27}

auto x2{1,2,3.0}; 推导不出来 std::initializer中的T

template

void f(T param);

f({1,2,3}); //错误,型别推导错误

可以转换成

template

void f(std::initializer_list initlist);

f({1,2,3});

c++14允许使用auto作为返回值类型,lambda式也会在形参声明中用到auto,但这些auto使用的是模板型与i到而非auto推导,若返回值是一个大括号括起来的初始化表达式会通不过编译。

decltype

1
2
3
4
5
const int&a=2;

auto b=a; //int
decltype(a) c=b; //const int&
decltype(auto)d=a; //const int&

函数返回值

template<typename Container, typename Index>

  • auto …(){…return c[i];} //int
  • auto …()->decltype(c[i]){…} //int&
  • decltype(auto)…{} //int&
  • decltype(auto)…(Container&& c,…){…return std::forward©[i]}
  • auto…->decltype(std::forward©[i])(Container&& c,…){…return std::forward©[i]}

后面两个可以防止出现出现对临时变量的引用