背景
在模板中有传值和传引用两种方式,不过传引用又可以分为const和non-const两种方式,在一些源码中经常充斥着模板编程,如果对类型推导不熟悉,很多时候想当然的结果会有很大误差,下面具体来分析。
传值
在传值之前,我们首先熟悉以下字面常量的类型,比如“hello”的数据类型是const char[6], 这里的6是因为尾部有个结束符,所以长度为5+1。下面先说两个传值时候类型推导遵循的结论:
- 传值会把类型的const和volatile,&这些修饰符都给干掉
- 对于数组,会把num的信息给干掉,直接转为指针
- 无视左右值
template<typename T>
printV(T par)
{}
// demo
printV("hello");// T 被推导为const char*
//这里要重点说以下,这个数组为啥被推导为指针?这个是C语言的规定,这里有个大坑,就是类型中抛弃了6的信息,后面还要为此专门想办法解决。那么为啥const没有被干掉呢?这里说来话长,其实这里的const是*p的,不是P的。
int a = 1;
int& b = a;
const int& c = a;
printV(a);// T被推导为int
printV(b);// T被推导为int
printV(c);// T被推导为int
int d[3] = {1,2,3};
printV(d);// T被推导为int*
const int e[3] = {1,2,3};
printV(e);// T被推导为const int*, 和const char* 是一个德性;
int num = 3;
printV(std::move(num));// T被推导为int, 无视左右值
printV(3);// T被推导为int, 无视左右值
传const 引用
- T会被推导为裸类型
- 对于数组,会保留num的信息,且为数组类型
- 无视左右值
- 对于指针,最好不要传了,T会被推导int*, 但是int* const & par是啥已经有点看不懂了。
template<typename T>
void printV(const T& par)
{}
// demo
printV("hello");// T 被推导为char[6]
int a = 1;
int& b = a;
const int& c = a;
printV(a);// T被推导为int
printV(b);// T被推导为int
printV(c);// T被推导为int
int d[3] = {1,2,3};
printV(d);// T被推导为int[3]
const int e[3] = {1,2,3};
printV(e);// T被推导为int[3]
int num = 3;
printV(std::move(num));// T被推导为int, 无视左右值
printV(3);// T被推导为int, 无视左右值
传non-const引用
- 不支持右值(这里有个bug, const修饰的可以)
- 对于数组,数组保留num, 且为数组类型
一般用非const的时候,都是想在函数里面把值给改了,但是第一条有一个bug, 就是可以传入一个const对象,这就比较难受,为此需要下面处理:
template<typename T>
void printV(T& par)
{}
std::string const c = "hello";
printV(c);//T会被推导为const string, 这样在模板里就不能改这个数字了,
//日,以后C++学习先背书好了,这么多乱其八糟都需要记住
//解决
template<typename T, typename dummy = enable_if_t<!std::is_const<T>::value> >
void printV(T& par);