模版类型推导

简述

  • 采用如下方式讨论模版类型推导原则
//声明
template<typename T>
void f(ParamType param);
//调用
f(expr);
  • 根据ParamType的类型分为三类来阐述

    1. ParamType是指针或者引用(非universal reference,它与lvalue reference和rvalue reference不同)
    2. ParamType为universal reference
    3. ParamType非指针和引用

Case1

这是最简单的一种情况,它的工作过程如下:
1. 如果expr是一个引用类型,忽略引用部分
2. 之后expr与ParamType进行模式匹配来决定T

模版如下

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

声明以下变量,则推导如注释所示

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

f(x); // T->int, ParamType->int
f(cx); // T->const int, ParamType->const int&
f(rx); // T->const int, ParamType->const int&

可见后两者的const都被推导到了T类型中,这也就导致了ParamType具有了const属性,从而维护了调用者的原意:保证引用参数的常量性。


该用模版如下,为param添加const属性

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

声明以下变量,则推导如注释所示,并没有什么特别大的变化,只是T不再附加const,因为param已经具备的const

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

f(x); // T->int, ParamType->int
f(cx); // T->int, ParamType->const int&
f(rx); // T->int, ParamType->const int&

对于ParamType为指针类型模版,如下

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

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

推导规则与引用的是一样一样的。

Case2

universal reference的声明类型类似右值引用 T&&,推导规则如下:
1. 如果expr为lvalue,T和ParamType全部推导为lvalue reference。这存在两个不同点:1. 这是在模版类型推导中唯一的一种情况:T推导为引用类型。2.虽然ParamType采用T&& 右值引用的声明语法,但是实际推导出的类型为lvalue reference。
2. 如果expr为lvalue,则采用Case1的推导方式。

template <typyname T>
void f(T&& param); //universal reference T&&

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

f(x); //lvalue, T->int&, ParamType->int&
f(cx); //lvalue, T->const int&, ParamType->const int&
f(rx); //lvalue, T->const int&, ParamType->const int&
f(27); //rvalue, T->int, ParamType->int&&
//后期解释为什么,关键在于unisersal reference对于lvalue和rvalue的推导是不同的

Case3

情形如下

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

可见参数按值传递,每次param都是一个拷贝,一个新的对象。
这也就决定了我们如何确定推导规则:
1. 如果expr是一个引用类型,忽略引用部分。
2. 如果忽略了引用之后,expr含有const,同样忽略;如果有volatile,忽略

int x = 27;
const int cx = x;
const int& rx = x;
f(x) //T->int, ParamType->int
f(cx) //T->int, ParamType->int
f(rx) //T->int, ParamType->int

小节

个人理解:对于模版类型推导,也就是根据用户所传递参数的类型expr以及提供的函数模版形式,综合二者来推测函数调用者的原意,再找到能够体现这种原意的最合适的推导结果,也就是T和ParamType。
Case1中引用或者指针都代表(指向)着一个已存在的对象,对象的const、volatile属性是需要保留的,所以最终形成的ParamType都将具备这些属性。
Case2还没有太理解。
Case3之所以抛弃掉了const、volatile属性,是因为值传递的话是一个拷贝过程,与用户传递的参数属性并不意味着一定要做用到那个拷贝身上。
对于const char* const 类型的expr,推导如下,同样要保持用户的原意

const char* const ptr = "hello world";
f(ptr); //T->const char*, ParamType->const char*

Arrays and Function Argument

Arrays

  • 数组类型和指针类型
    数组类型和指针类型是两种不同的类型,在很多情况下一个array可以蜕化成为一个指向array第一个元素的指针。所以以下代码可以通过编译
const char name[] = "hello world"; //name类型是const char[12]
const char *ptrToName = name; //蜕化为const char*
  • array在传值模版中的推导
template<typename T>
void f(T param);

f(name); // T->const char*
/*这是因为在C语言中
void f(int param[]);
等价于
void f(int *param);
*/
  • array在传引用模版中的推导
template<typename T>
void f(T& param);

f(name); //T->const char[12], ParamType->const char(&)[12]

function

数组不是唯一的蜕化为指针的东西,函数同样也蜕化为指针。

void someFunc(int ,double);
template<typename T>
void f1(T param); //by value
template<typename T>
void f2(T &param); //by ref

f1(someFunc); //ParamType->void(*)(int ,double)
f2(someFunc); //ParamType->void(&)(int ,double)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值