Traits编程技法——STL源码剖析
根据《C++ primer》16.2 我们知道,编译器无法推断函数返回值的模板实参的类型:
template<typename T1,typename T2,typename T3>
T1 sum(T2,T3);
对于上面的例子,编译器无法推断T1的类型,必须提供一个显式模板实参,例如:
auto val=sum<int>(1,2);
但是,这时候必须由用户显式提供,否则就需要用其他方法。
迭代器所指对象的型别(类型),称为迭代器的value type。如果value type必须用于函数的返回值,需要声明内嵌型别(在《C++ primer》中翻译为内置类型)。
#include <iostream>
using namespace std;
template <class T>
struct MyIter {
typedef T value_type; // 内嵌型别声明
T* ptr;
MyIter(T* p = 0) :ptr(p) {}
T& operator*() const { return *ptr; }
};
template<class I>
typename I::value_type
func(I ite){
return *ite;
}
int main(){
MyIter<int> ite(new int(8));
cout<<func(ite); //输出8
}
由于无法推断函数func的返回类型,所以在MyIter类中声明了typedef T value_type
,然后func函数的返回值就可以写为typename I::value_type
,这样就达到了目的,这是《STL 源码剖析》中提供的。但达到这个目的其实还有一种方法,即用尾置返回类型:
template<class I>
//如果不想返回引用:
//auto func2(I ite)->typename remove_reference<decltype(*ite)>::type{
//返回的是引用
auto func2(I ite)->decltype(*ite){
return *ite;
}
但是,上面方法必须假定MyIter是一个类类型,这样才可以在类里面声明typedef T value_type
,如果是原生指针,上面的方法就不适用,这时候需要对它进行偏特化处理(偏特化在《C++ primer》中翻译为部分特例化,参考16.5,p628)。
用一个类模板专门萃取迭代器的特性,即为了实现typedef T value_type
template <class T>
struct my_iterator_traits
{
typedef typename T::value_type value_type;
};
注意:在这里,与书上代码有一处不同,书上模板名是iterator_traits
,而这里是my_iterator_traits
,如果不改变名字,无法运行成功。。。
之前的func函数就可以改写为:
template <class I>
typename my_iterator_traits<I>::value_type // 通过iterator_traits类萃取I的型别
func(I ite) {
return *ite;
}
此时,下面的main函数是可以运行成功的
int main(){
MyIter<int> ite(new int(8));
cout<<func(ite); //输出8
}
接下来,实现原生指针的偏特化,一个int *,一个const int *:
template <class T>
struct my_iterator_traits<T*>
{
typedef T value_type;
};
template <class T>
struct my_iterator_traits<const T*>
{
typedef T value_type;
};
总结
#include <iostream>
using namespace std;
template <class T>
struct MyIter {
typedef T value_type; // 内嵌型别声明
T* ptr;
MyIter(T* p = 0) :ptr(p) {}
T& operator*() const { return *ptr; }
};
template <class T>
struct my_iterator_traits
{
typedef typename T::value_type value_type;
};
template <class T>
struct my_iterator_traits<T*>
{
typedef T value_type;
};
template <class T>
struct my_iterator_traits<const T*>
{
typedef T value_type;
};
template <class I>
typename my_iterator_traits<I>::value_type // 通过iterator_traits类萃取I的型别
func(I ite) {
return *ite;
}
int main() {
MyIter<int> ite(new int(6));
cout << func(ite) << endl;//print=> 6
int *p = new int(7);
cout << func(p) << endl;//print=> 7
const int k = 8;
cout<< func(&k) << endl;//print=> 8
}