Traits編程技法

照順序,這次應該是迭代器Iterator的內容了,然而Iterator涉及到一個重要的技巧就是Traits編程技法。

一 獲取Iterator的相應類型(associate type)

在使用Iterator時,可能需要知道它的相應類型,也就是Iterator指向的變量的類型,在C/C++語言中,如果要獲取一個變量的大小可以使用sizeof()操作符。然而如果想要獲取一個指針指向的變量類型該如何做呢,可惜它沒有一個typeof()操作符供我們程序員使用。

利用template的引數/參數推導(argument deducation)是一個解決問題的好方法,僅將func函數作爲一個包裝,而把實際的操作放在一個函數func_impl裏面完成。一旦func()函數被調用,編譯器就自動進行引數推導,自動導出類型T。

#include <iostream>
using namespace std;

template<typename Point, typename T>
void func_imp(Point iter, T value)
{
	T tmp;     // 這裏推導出了iter的數據類型
	tmp = value;
	cout << tmp << " in " << __FUNCTION__ << endl;
}

template<typename Point>
void func(Point iter)
{
	func_imp(iter, *iter);
}

int main()
{
	int *a = new int;
	*a = 10;
	func(a);

	return 0;
}

現在解決了從指針中獲取原數據類型的方法,類型的的確確是獲取到了,但要將類型作爲一個函數的返回類型呢?有沒有什麼辦法提前獲取到類型呢,這就需要Traits編程技法了。

 Traits編程技法初見

採用nested type(巢狀型別)似乎是個不錯的注意,如下所示:

template<class T>
class Iterator {
public:
	typedef T value_type;
	T *m_ptr;
	Iterator(T *p = 0) : m_ptr(p) {}
	T& operator*()const { return *m_ptr;}	
};

template<class I>
typename I::value_type func2(I iter)
{
	return *iter;
}

int main()
{
	int *p = new int(8);
	Iterator<int> iter(p);
	cout << func2(iter) << endl;
	delete p;

	return 0;
}

首先構建Iterator類,獲取類型的方法和上文直接用兩層函數的方法相似。這裏func2函數的返回值前加上了一個typename,這是因爲在template T實例化之前,編譯器對T一無所知,並不知道Iterator<int>::value_type代表的是一個函數,變量還是類型。關鍵字typename就是告訴編譯器說這是一個類型,以使得編譯通過。

看起來不錯,但是這裏還有一個隱晦的陷阱:並不是所有的迭代器都有value_type,編譯器內嵌類型(原生指標)就沒有,這樣編譯就不能通過,但是STL必須接受原生指標作爲一種迭代器,這需要另外的技巧,它就是模板偏特化(template partial specialization)。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章