TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

c++11类型推导

参考

effective modern c++

https://medium.com/@tjsw/%E6%BD%AE-c-11-universal-reference-rvalue-reference-move-semantics-1ea29f8cabdc

C++11 新特性:decltype

模板类型推导

函数模板可以看成是这样:

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

分三种情况:

  • ParamType是一个指针或者引用(非通用universal reference引用)
  • ParamType是一个通用引用(universal reference)
  • ParamType既不是指针也不是引用

三种情况的推导规则:(推导规则推导的是T的类型)

1 ParamType是一个指针或者引用(非通用universal reference引用)

  • 如果expr的类型是引用,忽略引用的部分
  • 根据expr和ParamType对比来判断T的类型

2 ParamType是一个通用引用(universal reference)

  • 如果expr是个左值,T和ParamType都会被推导成左值引用
  • 如果expr是个右值,参考情况1

3 ParamType既不是指针也不是引用

  • 如果expr的类型是引用,忽略引用的部分
  • expr是cv的,也要忽略cv类型

实际测试:

case 1

1
2
3
4
5
6
7
8
9
10
template<typename T>
void f(T& param); // param是一个引用类型

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

f(x); //T: int param: int &
f(cx); //T: const int param: const int &
f(rx); //T: const int param: const int &

case 2

1
2
3
4
5
6
7
8
9
10
11
template<typename T>
void f(T&& param);

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

f(x); //T: int & param: int &
f(cx); //T: const int & param: const int &
f(rx); //T: const int & param: const int &
f(27); //T: int&& param: int &&

引用折叠(Reference collapsing)

A&&       --> A&
A&&&       --> A&
A&&&       --> A&
A&& &&      --> A&&

case2的param经过了引用折叠:

int & &&            -->     int &
const int & &&      -->     const int &
const int & &&      -->     const int &
int && &&           -->     int &&

case 3

1
2
3
4
5
6
7
8
9
10
template<typename T>
void f(T param);

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

f(x); //T: int param:int
f(cx); //T: int param:int
f(rx); //T: int param:int

数组参数

数组会退化为指针:

1
2
3
4
5
6
7
const char name[] = "J. P. Briggs"; // name的类型是const char[13] 
const char * ptrToName = name; //数组退化成指针

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

数组的引用会保留为数组形式:

1
2
3
4
const char name[] = "J. P. Briggs"; // name的类型是const char[13] 
template<typename T>
void f(T &param);
f(name); //T: const char[13] param: const char (&)[13]

函数参数

函数类型退化成函数指针:

1
2
3
4
5
6
void someFunc(intdouble);    //void (int, double)

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

f1(someFunc); //T: void (*)(int, double)

函数引用会保留为函数形式:

1
2
3
4
5
6
void someFunc(intdouble);    //void (int, double)

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

f2(someFunc); //T: void (&)(int, double)

auto类型推导

auto类型推导和模板类型推导基本一致,auto相当于T,只有一个例外:{}

1
2
3
4
5
6
7
auto x1 = 27;       //auto: int 
auto x2(27); //auto: int
auto x3 = {27}; //auto: std::initializer_list<int>
auto x4{ 27 }; //auto: std::initializer_list<int>

auto x5 = { 1, 2, 3.0 }; //编译失败,类型不一致

decltype

decltype可以表示变量或者表达式的类型

使用方式:

1
decltype(expr) a;   

注意点:

对一个变量名使用 decltype 得到这个变量名的声明类型。变量名属于左值表达式,但这并不 影响 decltype 的行为。然而,对于一个比变量名更复杂的左值表达式, decltype 保证返回 的类型是左值引用

1
2
3
int x = 0;
decltype(x) a; //a: int
decltype((x)) a; //a: int &

尾随返回值类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//c++11版本
//auto作为函数返回值,不能推导出c和i的类型,因为这时候c和i还没有声明
//通过--> decltype(c[i])表示函数返回值类型在函数参数后声明
template<typename Container, typename Index>
auto authAndAccess(Container& c, Index i)
-> decltype(c[i])
{
authenticateUser();
return c[i];
}

//c++14版本
//c++14这样是可以编译过的,但是auto进行了类型推导并不和c[i]类型一致
template<typename Container, typename Index>
auto authAndAccess(Container &c, Index i)
{
authenticateUser();
return c[i];
}

//c++14版本
//返回值类型和c[i]保持一致
template<typename Container, typename Index>
decltype(auto) authAndAccess(Container &c, Index i)
{
authenticateUser();
return c[i];
}

//使用完美转发更好,以后总结完美转发

特殊情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{

int &&j = int();
int a = 10;
auto &&b = std::move(a);
auto &&c = j;
j = 90;
cout << &j << endl;

//dd<decltype(j)> s; //dd<int&&> s
//dd<decltype(std::move(a))> s; //dd<int&&> s
//dd<decltype(b)> s; //dd<int&&> s
//dd<decltype(c)> s; //dd<int&> s
return 0;
}

j是左值,类似函数实参(形参是右值的,实参是左值;有名的右值引用是左值)。auto &&这种就是模板的perfect reference

ENDDING

070901.jpg

----------- ending -----------