2010-12-04 74 views
15

我將如何定義一個函數,該函數將迭代器作爲輸入傳遞給任何類型的STL容器,但僅限於特定模板類型的迭代器。例如:將STL迭代器放在特定類型的元素的任意容器上的函數

形式的任何迭代器std::list<Unit*>::iteratorstd::vector<Unit*>::iterator

我只想確定採取std::list<Unit*>::iterator的功能,但如果我們切換到不同的STL容器,我不希望有改變我的代碼。

有沒有辦法用模板或其他方式做到這一點?

+2

`std :: list`? STL容器中的原始指針?爾加! :) – 2010-12-04 19:22:37

回答

14

您可以使用SFINAE構造,如boost::enable_if,它驗證嵌套的typedef iterator::value_type是否確實是合適的類型。

template<class T, class Iterator> 
typename boost::enable_if<boost::is_same<typename Iterator::value_type, T> >::type 
    f(Iterator i) 
{ 
    /* ... */ 
} 

int main() 
{ 
    std::list<int> l; 
    std::vector<int> v; 

    f<int>(l.begin()); // OK 
    f<int>(v.begin()); // OK 

    std::vector<float> v2; 
    f<int>(v2.begin()); /* Illegal */ 
} 

這是我從理解「是作爲輸入迭代器在任何類型的STL容器的功能,但只對那些特定的模板類型的」,但我的理解可能是錯誤的。

+0

這對我來說是一個非常有用的答案。謝謝! – 2011-06-16 15:51:07

6

你只想遍歷my_special_type的容器?在這種情況下:

template <bool, typename T> 
struct enable_if; 

template <typename T> 
struct enable_if<true, T> 
{ 
    typedef T type; 
}; 

template <typename T, typename U> 
struct is_same 
{ 
    enum {value = false}; 
}; 

template <typename T> 
struct is_same<T, T> 
{ 
    enum {value = true}; 
}; 

template <typename Iter> 
typename enable_if<is_same<typename Iter::value_type, your_special_type>::value, 
        void>::type 
function(Iter begin, Iter end) 
{ 
    // ... 
} 
+0

有趣!但是,如果函數與錯誤類型一起使用,會發生什麼?對不起,如果這是微不足道的。我仍然在學習模板。 – RyanG 2010-12-04 17:42:37

5

模板的另一種方式是在條件不滿足時觸發靜態斷言。

#include <iterator> 
#include <boost/type_traits/is_same.hpp>  
#include <boost/static_assert.hpp> 

template <class Type, class Iter> 
void foo(Iter from, Iter to) 
{ 
    BOOST_STATIC_ASSERT((boost::is_same<typename std::iterator_traits<Iter>::value_type, Type>::value)); 
    //... 
} 

int main() 
{ 
    int arr[10]; 
    foo<int>(arr, arr + 10); //OK 
    foo<double>(arr, arr + 10); //triggers static assertion 
} 

如果您不想使用模板,那麼也可以使用類型擦除來編寫「any_iterator」。例如,像這樣的:http://stlab.adobe.com/classadobe_1_1any__iterator.html

14

除了依靠SFINAE現有的答案,一個簡單的近似值是簡單地定義函數取任意模板類型的迭代器:

template <typename Iter> 
void function(Iter first, Iter last){ 
    Unit* val = *first; 
} 

這有一些缺點。與SFINAE解決方案(例如boost::enable_if)不同,這不會給你確切的你所要求的。只要Iter類型的對象可以被取消引用,就可以編譯,產生一個值,可以轉換爲Unit*,這是不完全相同的事情。您不能保證Iter是完全符合STL標準的迭代器(它可能只是另一種類型,它定義了operator*),或者它的值類型精確地爲Unit*

另一方面,它更簡單。

0

嗯,我會使用的情況下,簡單的typedef,你只需要一個容器類型的時候(如果我理解你的用例,正確是這種情況)

template <class T> 
class ContainerIterator 
{ 
    Container(); 
    public: 
    typedef std::list<T>::iterator type; 
} 

//usage: 
void function(ContainerIterator<YourType>::type begin, ContainerIterator<YourType>::type end) 
{ 
    //... 
} 

稍後切換容器,只需更改typedef中的容器類型即可。