如何将迭代器限制为前向迭代器?

时间:2012-01-05 23:32:24

标签: c++ templates iterator

我有一个需要多次枚举迭代器的函数,但是according to MSDN“一旦递增输入迭代器的任何副本,其他任何副本都不能安全地进行比较,解除引用或者之后递增。“

因此,为了简化操作,我不想为复制数据和枚举副本的非正向迭代器创建单独的实现,而是希望将我的方法限制为只接收前向迭代器,并静态拒绝输入迭代器。 / p>

现在我有类似的东西:

template<typename It, typename TCallback /*signature: bool(value_type)*/>
bool EnumerateTwice(const It &begin, const It &end, TCallback callback)
{
    for (It it = begin; it != end; ++it)
        if (!callback(*it))
            return false;
    for (It it = begin; it != end; ++it)
        if (!callback(*it))
            return false;
    return true;
}

但没有任何限制It成为前向迭代器。

如何将限制放在模板化函数上? (C ++ 03)

4 个答案:

答案 0 :(得分:5)

您可以使用SFINAE并将bool替换为:

typename enable_if<
   is_same<typename std::iterator_traits<It>::iterator_category,
           std::forward_iterator_tag>::value,
   bool>::type

如果您不想从Boost或TR1中提取is_sameenable_if,则可能需要自己定义:

template <typename A, typename B>
struct is_same { static const bool value = false; };

template <typename T>
struct is_same<T, T> { static const bool value = true; };

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

答案 1 :(得分:4)

未经测试但您可以尝试以下方式:

template<typename It, typename TCallback /*signature: bool(value_type)*/>
bool EnumerateTwice_Interal(const It &begin, const It &end, TCallback callback, 
      std::forward_iterator_tag)
{
     //do your things
}

template<typename It, typename TCallback /*signature: bool(value_type)*/>
bool EnumerateTwice(const It &begin, const It &end, TCallback callback)
{
    EnumerateTwice_Internal(begin, end, callback,
        typename std::iterator_traits<It>::iterator_category());
}

答案 2 :(得分:3)

您可以使用std::enable_if

执行此操作
#include <iterator>
#include <type_traits>
#include <utility>

template <typename It, typename TCallback>
typename std::enable_if<std::is_base_of<std::forward_iterator_tag,
                        typename std::iterator_traits<It>::iterator_category>::value,
                    bool>::type
EnumerateTwice(It begin, It end, TCallback) {
    ...
}

这使用了C ++ 11中的类,但所有这些都可以在C ++ 03中完成。

答案 3 :(得分:0)

为了扩展罗德里戈的答案 - 我找到了这个解决方案,并认为值得一提:

struct True { unsigned char _[2]; operator bool() const { return true; } };
char is_forward_iterator(std::input_iterator_tag const *) { return 0; }
True is_forward_iterator(std::forward_iterator_tag const *) { return True(); }

现在,如果您想在某个功能中查看它,您可以说:

if (is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0)))
{
    ...
}

如果您想在模板中查看,可以查看:

sizeof(
  is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0))
) > 1

这种方法的主要优点是避免声明模板(例如,为了更好的编译速度)。