最近在學習《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等,就是這個道理。