模板的参数推导机制
模板的参数推导机制
在算法中,我们很有可能需要使用迭代器所指之物的型别,这该如何是好呢,毕竟c++只支持sizeof(),并不支持typeof()!即使是动用RTTI性质中的typeid(),获得的也只是型别名称,不能拿来声明变量,这就需要参数推导机制,我们今天就来看一下c++高级技巧----模板的参数推导机制。
#include <iostream>
template <class T, class I>
void fun_1(I iter, T t) {
T tmp = 0; // 这里解决了问题。T就是指针所指之物的型别。
std::cout << tmp << std::endl;
}
template <class I>
inline void fun_2(I iter) {
fun_1(iter, *iter); // fun2的工作全部移动到fun1上
}
/*
上面虽然推出了T的类型,但是如果T必须用于函数的返回值 ,上面的参数推导就无法解决了
该如何解决这个问题呢? 使用内嵌类型是个好方法
*/
template <class T>
struct MyIter {
typedef T value_type; // 内嵌类型
T* ptr;
MyIter(T* p): ptr(p){}
T& operator*() const {
return *ptr;
}
// ...
};
template <class I>
typename I::value_type // 这个行是func的回返值型别
func(I ite) {
typename I::value_type x = 0;
std::cout << x << std::endl;
return *ite; // 不但推出了参数而且可以用于函数返回值的推导
}
/*
这里需要使用typename的原因是:因为T是一个template参数,在被编译器具现化之前,编译器对T一无所知,
换句话说,编译器此时并不知道MyIter<T>::value_type是个型别,typename就是告诉编译器这是一个型别,如此才能顺利通过编译
*/
/*
看起来已经很强大了,但是如果T本身就是一个原生指针呢? 上面的办法就无法实现了
这时候就需要用到另一个强大的技巧,那就是模板的偏特化,接下来我们一起来看
*/
template <typename T> // 一个类模板
struct C{
typedef T value_type; //这里可以推出T的版本
};
template<typename T>
struct C<T*> { // C类型的偏特化版本,本质上还是一个类模板,只是加上了一点约束
typedef T value_type; // 对模板类实例化为C<int*> value_type本质上其实推断出还是int // 可以接受const int* 但却推出了const int
};
template<typename T>
struct C<const T*> {
typedef T value_type; // 我们推断出T的类型就是要用的,如果成了const无法赋值那不就没用了
// 这样还是推出了T的类型
};
int main()
{
int i = 0;
fun_2(&i); // 参数推导
MyIter<int> x(new int(9));
std::cout << func(x) << std::endl; // 使用内嵌型别,T可用于函数返回值的推导
C<int>::value_type a = 0;
C<int*>::value_type b = 1;
C<const int*>::value_type c = 2;
c = 3; // c的类型其实是int
std::cout << a << b << c << std::endl;
return 0;
}
/*
输出为:
0
0
9
013
*/
参数推导机制是一个非常高阶的技巧,本人才疏学浅,理解不深,只是凭自己的理解和参考《STL源码刨析》进行学习,如有问题可以联系博主一起探讨。