traits編程技巧

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

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