Effective modern C++(SECTION 1)

模板型别推到

template <typename T>
void func(ParamType param){

}
func(expr);

对于上面的型别推导,编译器主要需要推导ParamType,T的型别。ParamType常会包含一些饰词,如const或者引用符号等限定词

三种情况

1. ParamType是一个指针或引用,但不是万能指针

(1)、如果expr具有引用类型,则先忽略其引用部分

(2)、然后,对expr的型别和ParamType的型进行匹配,决定T的型别

如下:

template <typename T>
void f(T& param);
int x = 27;
const int cx = x;
cosnt int &rx = x;

f(x); // param的型别是int&, T的型别是int
f(cx) // param的型别是const int&, T的型别是const int
f(rx) // param的型别是const int&, T的型别是const int
    
template <typename T>
void f(const T& param);
int x = 27;
const int cx = x;
cosnt int &rx = x;

f(x); // param的型别是const int&, T的型别是int
f(cx) // param的型别是const int&, T的型别是int
f(rx) // param的型别是const int&, T的型别是int

2.ParamType是一个万能引用(T&&)

(1)、如果expr是一个左值,T和ParamType都被推到为左值引用。特殊性:这是在模板型别推导中,T被推导为引用型别的唯一情形。
(2)、如果expr是一个右值,则应用情况1中的规则。

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

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

f(x); //x是左值,所以T的型别为int &, param的型别也是int&

f(cx); //cx是左值,所以T的型别是const int&, param也是const int&

f(rx); //rx是左值,所以T的型别为const int&, param也是const int&

f(27); //27是右值,所以T的型别为int, param是int &&

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

其实就是按值传递,无论传入是什么,param都会是一个副本(全新对象)

推导过程如下:

(1)、首先忽略expr的引用性

(2)、忽略顶层const,volatile

总结

1、在模板型别推导过程中,具有引用型别的实参会被当成非引用型别来处理,即其引用性会被忽略

2、对于万能引用形参进行推导,左值实参会被推到为左值引用

3、对按值传递的形参进行推导,若实参型别中带有const或volatile饰词,推导时会被忽略(顶层const被忽略)

4、数组或函数型别会退化为对应的指针,除非被用来初始化引用

auto型别推导

与模板型别推导类似

auto x = 27; //型别饰词既不是指针,也不是引用, 情况3
const auto cx = x; //型别饰词既不是指针,也不是引用, 情况3
const auto& rx = x; //型别饰词包含引用,情况1
auto&& uref1 =x; //x是int,左值, uref1的型别为int&
auto&& uref2 = cx; // uref2的型别是const int &
auto&& uref3 = 17; //uref3的型别是int&&

decltype类型推导

对于给定的名字或表达式,decltype可以给出名字和表达式的型别,是什么,推导出就是什么。

常用于声明返回值型别依赖于形参型别的函数模板,如下:

template <typename T>
auto authAndAccess(Containter& c, int i)
-> decltype(c[i])
{
    return c[i];//若是引用类型,返回引用类型,即根据c[i]的型别确定返回值类型
}

其中, auto不进行型别推导,只是说明这里使用C++11中的返回值型别尾序语法.

C++14进一步引入decltype(auto)饰词

template <typename T>
decltype(auto)
authAndAccess(Container& c, int i){
    return c[i];
}

Widget w;
const Widget& cw = w;
auto myWidget1 = cw; //myWidget1的型别是Widget
decltype(auto) myWidget2 = cw; //myWidget2的型别是const Widget&

int x = 0;
(x)是一个左值, 型别是int&

评论区 0