推导类型
1. 理解类型推导
auto的推导方式和template是一样的,所以我们首先来介绍template是如何推导类型的。
template <typename T>
void f(const T& orig) {
cout << __PRETTY_FUNCTION__ << endl;
cout << typeid (orig).name() << endl;
cout << typeid (T).name() << endl;
}
int x = 10;
f(x);
/*
void f(const T &) [T = int]
i
i
*/
T和orig的类型一样的,这很奇怪吧。实际上,template类型推导有三个情况:
-
- orig是一个指针或者引用类型,但不是全局引用(universal reference)
-
- orig是一个全局引用。
-
- orig即使不是指针也不是引用。
template <typename T>
void f(ParamType param);
f(expr)
情况1 :ParamType是一个指针或者引用类型,但不是全局引用(universal reference)
在这种情况下,
-
- 如果expr的类型是一个引用,忽略引用的部分。
-
- 把expr的类型与ParamType的类型比较,用来判断T的类型。
例如:
template <typename T>
void f(T& param) {
cout << __PRETTY_FUNCTION__ << endl;
}
int main(int argc, char *argv[]) {
int y = 10;
f(y);
const int x = y;
f(x);
const int& z = y;
f(z); // ignore the reference.
return 0;
}
void f(T &) [T = int]
void f(T &) [T = const int]
void f(T &) [T = const int]
这就是为什么一个const对象传给模板后是安全的,因为const性质会成为模板推导的一部分。
我们注意到第三个例子中,T被推导为const int,是因为忽略了&, 如果不这样,ParamType 会被推导为const int&&,这是不被允许的。
我们这里提及的都是左值引用,实际上右值引用也是一样的,但是右值引用只能传递给右值引用,虽然这个类型推导关系不大。
我们来做一个小小的修改。
template <typename T>
void f(const T& param) {
cout << __PRETTY_FUNCTION__ << endl;
}
int main(int argc, char *argv[]) {
int y = 10;
f(y);
const int x = y;
f(x);
const int& z = y;
f(z); // ignore the reference.
return 0;
}
void f(const T &) [T = int]
void f(const T &) [T = int]
void f(const T &) [T = int]
同样的,T的引用被忽略了,const属性也被忽略了。因为对于param而言总是const。
对于指针:
template <typename T>
void f(T* param) {
cout << __PRETTY_FUNCTION__ << endl;
}
int main(int argc, char *argv[]) {
int y = 10;
f(&y);
const int x = y;
f(&x);
const int& z = y;
f(&z); // ignore the reference.
const int* p = &z;
f(p);
return 0;
}
void f(T *) [T = int]
void f(T *) [T = const int]
void f(T *) [T = const int]
void