传递迭代器而不是容器

时间:2012-04-13 17:14:35

标签: c++ iterator containers

目前,我遇到了一些代码,例如fooA()(不介意正文),它需要一个特定的容器,比如vector<double>作为参数。

double fooA(std::vector<double> const& list)
{
    return list[0];
}

现在,我想概括并使用迭代器:

template<typename InputIterator>
double fooB(InputIterator first, InputIterator last)
{
    return *first;
}

如何声明fooB()要求迭代器迭代double

有人可能会传递vector<string>::iterator,或者更糟糕的是,它可能会在没有警告的情况下编译vector<int>::iterator

2 个答案:

答案 0 :(得分:4)

对于C ++ 03:

#include <iterator>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/utility/enable_if.hpp>

template<typename InputIterator>
typename boost::enable_if<
    boost::is_same<
        typename boost::remove_cv<
            typename std::iterator_traits<InputIterator>::value_type
        >::type,
        double // expected value_type
    >,
    double     // fooB return type
>::type
fooB(InputIterator first, InputIterator last)
{
    return *first;
}

另一个不使用Boost的C ++ 03解决方案,但在传递无效类型时可能会产生更多的错误:

#include <iterator>

void fooB_helper(double) { }
template<typename T> void fooB_helper(T const&);

template<typename InputIterator>
double fooB(InputIterator first, InputIterator last)
{
    fooB_helper(typename std::iterator_traits<InputIterator>::value_type());
    return *first;
}

对于C ++ 11,您可以使用表达式SFINAE而不是enable_if,或者您可以使用static_assert代替SFINAE。

答案 1 :(得分:0)

如果您不想使用Boost / C ++ 11,您可能可以使用这种方法:

template<typename B, template<typename A1, typename B1> class Container>
double fooB(typename Container<int, B>::iterator first,
   typename Container<int, B>::iterator last)
{
  return 0;
}

致电:

vector<int> a;
fooB<vector<int>::allocator_type, vector>(a.begin(), a.end());

有点难看,但有效:)

另外:非可移植,因为std集合实现可以有两个以上的模板参数(第二个是具有默认值的分配器)