【问题标题】:How to check that the passed Iterator is a random access iterator?如何检查传递的迭代器是随机访问迭代器?
【发布时间】:2011-05-17 11:24:50
【问题描述】:

我有以下代码,它执行一些迭代算法:

template<class Iterator>
void Foo(Iterator first, Iterator last) {
  typedef typename Iterator::value_type Value;
  std::vector<Value> vec;
  vec.resize(last - first);
  // ...
}

(last - first) 表达式 (AFAIK) 仅适用于随机访问迭代器(例如来自 vectordeque 的迭代器)。如何检查传递的迭代器满足此要求的代码?

【问题讨论】:

  • 您可以使用distance(first, last) 完全避免检查。
  • 这可能适用于您的特定用例,但一般来说,您不能依赖“随机访问”标签来说明迭代器指向的内存是连续的。查看 Microsoft 的 concurrent_vector 类的文档。随机访问仅意味着您有一个迭代器可以理解的 [] 运算符。另外,如何处理随机访问的反向迭代器?我有一个类似的问题,我在这里寻找答案:Filtering Iterators
  • @KentKnox:谁说过内存是顺序的? last-first 适用于所有随机访问迭代器,包括std::deque::iterator,它肯定不指向顺序内存。

标签: c++ stl iterator


【解决方案1】:

如果Iterator是一个随机访问迭代器,那么

std::iterator_traits<Iterator>::iterator_category

将是std::random_access_iterator_tag。实现这一点的最简洁方法可能是创建第二个函数模板并让Foo 调用它:

template <typename Iterator>
void FooImpl(Iterator first, Iterator last, std::random_access_iterator_tag) { 
    // ...
}

template <typename Iterator>
void Foo(Iterator first, Iterator last) {
    typedef typename std::iterator_traits<Iterator>::iterator_category category;
    return FooImpl(first, last, category());
}

这样做的好处是,您可以根据需要为不同类别的迭代器重载 FooImpl

Scott Meyers 在一本Effective C++ 书中讨论了这种技术(我不记得是哪一本了)。

【讨论】:

  • 确实,这正是std::distance 在我正在查看的 g++ 实现中使用的技术 (4.3.2)
  • @Fred 和 std::advance() 也是。
  • 其他选项包括 (a) 添加无操作功能检查(例如 first + 0;),(b) 使用显式模板特化,或 (c) 使用 SFINAE 重载。但是,我不认为其中任何一个都像标签调度方法那样干净或直接。
【解决方案2】:

除了标签dispatch之外,还可以直接使用std::is_same_v比较类别与std::random_access_iterator_tag

using category = typename std::iterator_traits<Iterator>::iterator_category;
if constexpr (std::is_same_v<category, std::random_access_iterator_tag>) {
  vec.resize(last - first);
}

这有时会导致代码更加清晰和简洁,尤其是当您的实现只有一小部分(如保留向量大小)取决于迭代器类别时。

【讨论】:

  • 如果非随机访问迭代器出错,可以使用static_assert。另外我会考虑std::is_convertible_v 而不是std::is_same_v,因为前者允许某些未来版本的C++ 通过继承具有另一个类型标记,该类型标记也是std::random_access_iterator_tag。迭代器标签已经使用继承来表达 is-a 关系。
猜你喜欢
  • 2022-11-14
  • 2017-09-02
  • 2020-04-23
  • 1970-01-01
  • 2015-02-18
  • 2016-04-09
  • 2019-12-06
  • 1970-01-01
  • 2015-12-04
相关资源
最近更新 更多