[effective modern c++][1]理解模板类型推断

c++11 最终要的是拓展了类型推断(type deduction)使用的地方,比如autodecltype等。所以要详细的理解类型推断,以正确的使用。
类型推断时,在如下代码中,我们要确定TParamType的类型。

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

f(expr);

依据ParamType的不同,有三种情况需要讨论

  1. ParamType是引用或者指针,但不是universal references
  2. ParamTypeuniversal references
  3. ParamType既不是引用也不是指针

ParamType是引用或者指针,但不是universal references

这种情况下,T的类型推断遵循两个规则:

  1. 如果expr是引用类型,忽略引用部分
  2. exprParamType进行,模式匹配,差异的地方决定了T的类型

下面是例子:

// case 1
templaye<typename T>
void f(T& param);

int x = 27;                 // x 是 int
const int cx = x;           // cx 是 const int
const int& rx = x;          // rx 是 const int 的引用

f(x);                       // T is int, param's type is int&
f(cx);                      // T is const int, param's type is const int&
f(rx);                      // T is const int, param's type is const int&

// case 2
templaye<typename T>
void f(const T& param);

int x = 27;                 // x 是 int
const int cx = x;           // cx 是 const int
const int& rx = x;          // rx 是 const int 的引用

f(x);                       // T is int, param's type is const int&
f(cx);                      // T is int, param's type is const int&
f(rx);                      // T is int, param's type is const int&

// case 3
templaye<typename T>
void f(T* param);

int x = 27;                 // x 是 int
const int *px = &x;         // px 是一个指向 const int 的指针

f(&x);                      // T is int, param's type is int*
f(px);                      // T is const int, param's type is const int*

ParamTypeuniversal references

这种情况下,TParamType的类型推断遵循两个规则:

  1. 如果expr是左值,TParamType都会被推断为左值引用。这是在类型推断中,唯一出现引用的地方。
  2. 如果expr是右值,则回到第一种情况。

下面是例子:

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

int x = 27;
const int cx = x;
cont 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&&

ParamType既不是引用也不是指针

在这种情况下,参数使用值传递
此时,使用如下规则:

  1. 如果expr是引用,忽略引用部分
  2. 如果,在忽略了expr引用部分后,exprconst, volatile,同样被忽略。

下面是例子:

template<typename T>
void f(T param);        // param 是值传递

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

f(x);           // T 是 int,param 是 int
f(cx);          // T 是 int,param 是 int
f(rx);          // T 是 int,param 是 int

考虑一种情况,expr是一个指向常量对象的常量指针。

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

const char* const ptr = "fun with pointers";

f(ptr);     // T 是 const char *, param 是 const char *

特殊的情况:数组参数

需要知晓的是,数组并不同于指针

const char name[] = "J. P. Briggs";     // name 的类型是 const char[13]
const char * ptrToName = name;          // ptrToName 的类型是 const char *

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

f(name);                                // T 是 const char *,param 是 const char * 

虽然,函数不能接受数组参数,但是能够接受数组引用作为参数,所以

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

f(name);                    // T 是 const char[13],param 是 const char(&)[13]

有意思的是,正因为数组引用这种看起来奇怪的推断,导致我们能够在模板中推断出数组长度

template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept {
    return N;
}

函数参数

除了数组,函数也能被隐式推断为指针。

void someFunc(int, double);

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

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

f1(someFunc);       // T 是 void(*)(int, double), param 是 void(*)(int, double)
f2(someFunc);       // T 是 (void)(int, double), param 是 void(&)(int, double)

虽然,在使用上,函数的引用和函数的指针,没有什么显著的区别,但是还是要注意到类型推断上的不同。

牢记

  1. 类型推断时,引用参数被当做非引用参数对待,也就是说,他们的引用被忽略了。
  2. 当推断类型是universal reference参数时,左值被特殊对待了。
  3. 当推断类型是值传递时,constvolatile都被忽略了。
  4. 在模板类型推断时,数组和函数被隐式推断成了指针,除非param是个引用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值