最近在学习《STL源码剖析》,对书中介绍的traits很有感。
搜到的前辈的博客,这篇博文写的很好,感谢。
自己在写一下,加深自己的理解。
举例:加入我们现在有一个算法,可以对传入的迭代器前进N步。
template <typename ITERATOR>
void move_n_step(ITERATOR &itor, int n)
{
for (int i = 0; i < n; i++)
itor++;
}
代码很了然,然后我们有两个迭代器,分别是链表迭代器和数组迭代器。
class list_itor
{
public:
void operator++(int)
{
std::cout << "list_iter: " << __func__ << std::endl;
}
};
class array_itor
{
public:
void operator++(int)
{
std::cout << "array_iter: " << __func__ << std::endl;
}
};
为了方便期间,这两个迭代器只实现了后置++操作。
下面是第一版程序:
#include <iostream>
template <typename ITERATOR>
void move_n_step(ITERATOR &itor, int n)
{
for (int i = 0; i < n; i++)
itor++;
}
class list_itor
{
public:
void operator++(int)
{
std::cout << "list_iter: " << __func__ << std::endl;
}
};
class array_itor
{
public:
void operator++(int)
{
std::cout << "array_iter: " << __func__ << std::endl;
}
};
int main()
{
list_itor li;
array_itor ai;
move_n_step(li, 2);
move_n_step(ai, 3);
return 0;
}
但是,我们发现,对于数组性迭代器,我们也是采用++的方式前进,而数组型迭代器是支持算数运算的。
所以我们实现了2个算法,一个处理链表迭代器,一个处理数组迭代器。
#include <iostream>
template <typename ITERATOR>
void move_n_step_list(ITERATOR &itor, int n)
{
for (int i = 0; i < n; i++)
itor++;
}
template <typename ITERATOR>
void move_n_step_array(ITERATOR &itor, int n)
{
itor.operator+(n);
}
class list_itor
{
public:
void operator++(int)
{
std::cout << "list_itor: " << __func__ << std::endl;
}
};
class array_itor
{
public:
void operator+(int n)
{
std::cout << "array_itor: " << __func__ << std::endl;
}
};
int main()
{
list_itor li;
array_itor ai;
move_n_step_list(li, 2);
move_n_step_array(ai, 3);
return 0;
}
这下,好了,数组型迭代器可以发挥自己随机访问的优势了,但是,这颗毒瘤留给了使用这些算法的客户。他要时刻记着他用的是链表迭代器还是数组迭代器。
此时,traits登场(应有掌声)
traits就是个特性渣取机,它能识别出来一个迭代器是链表的还是数组的,是不是很NB。其实,说白了,也就那回事。
#include <iostream>
class list_itor
{
public:
void operator++(int)
{
std::cout << "list_itor: " << __func__ << std::endl;
}
};
class array_itor
{
public:
void operator+(int n)
{
std::cout << "array_itor: " << __func__ << std::endl;
}
};
// 定义两种迭代器的类型,仅仅为了实现函数重载
struct list_itor_type {};
struct array_itor_type {};
template <typename ITERATOR>
struct traits
{
};
// 针对链表迭代器的特化
template <>
struct traits<list_itor>
{
typedef list_itor_type itor_type;
};
// 针对数组迭代器的特化
template <>
struct traits<array_itor>
{
typedef array_itor_type itor_type;
};
// 内部方法,不应该暴露
template <typename ITERATOR>
void __move_n_step(ITERATOR &itor, int n, list_itor_type)
{
for (int i = 0; i < n; i++)
itor++;
}
// 内部方法,不应该暴露
template <typename ITERATOR>
void __move_n_step(ITERATOR &itor, int n, array_itor_type)
{
itor.operator+(n);
}
// 外部方法,供客户调用
template <typename ITERATOR>
void move_n_step(ITERATOR &itor, int n)
{
__move_n_step(itor, n, typename traits<ITERATOR>::itor_type());
}
int main()
{
list_itor li;
array_itor ai;
// 客户再也不想要时刻记者用的是什么迭代器了
move_n_step(li, 2);
move_n_step(ai, 3);
return 0;
}
是不是很爽,读STL源码,就会发现,各种容器与迭代器都要实现value_type,pointer_type,difference,reference等,就是这个道理。