将STL迭代器作为特定类型元素的任何容器的函数

时间:2010-12-04 17:03:01

标签: c++

如何定义一个函数,该函数将迭代器作为任何类型的STL容器的输入,但仅限于特定模板类型的那些。例如:

std::list<Unit*>::iterator std::vector<Unit*>::iterator

形式的任何迭代器

我只想定义函数std::list<Unit*>::iterator,但如果我们切换到不同的STL容器,我不想更改我的代码。

有没有办法用模板或其他方式做到这一点?

5 个答案:

答案 0 :(得分:15)

您可以使用SFINAEboost::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容器的输入,但仅限于特定模板类型的那些”,但我的解释可能是错误的。

答案 1 :(得分:14)

除了依赖SFINAE的现有答案之外,更简单的近似是简单地定义函数以将任意模板类型作为迭代器:

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

这有一些缺点。与SFINAE解决方案(例如boost::enable_if)不同,这不会为您提供完全您要求的内容。只要类型Iter的对象可以被解除引用而产生值可转换为Unit* ,就会编译,这不是完全相同的事情。您无法保证Iter是完全符合STL的迭代器(它可能只是定义operator*的另一种类型),或者它的值类型是Unit*。{/ p>

另一方面,它更简单。

答案 2 :(得分: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)
{
    // ...
}

答案 3 :(得分: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

答案 4 :(得分: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中的容器类型。