C++ 如何检查传递的迭代器是否为随机访问迭代器?

C++ 如何检查传递的迭代器是否为随机访问迭代器?,c++,stl,iterator,C++,Stl,Iterator,我有以下代码,它执行一些迭代器算法: template<class Iterator> void Foo(Iterator first, Iterator last) { typedef typename Iterator::value_type Value; std::vector<Value> vec; vec.resize(last - first); // ... } 模板 void Foo(迭代器优先,迭代器最后){ typedef typen

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

template<class Iterator>
void Foo(Iterator first, Iterator last) {
  typedef typename Iterator::value_type Value;
  std::vector<Value> vec;
  vec.resize(last - first);
  // ...
}
模板
void Foo(迭代器优先,迭代器最后){
typedef typename迭代器::value_type value;
std::vec;
调整向量大小(最后一个-第一个);
// ...
}

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

如果
迭代器是随机访问迭代器,则

std::iterator_traits<Iterator>::iterator_category
这样做的好处是,如果愿意,可以为不同类别的迭代器重载
FooImpl


Scott Meyers在一个有效的C++书籍中讨论了这个技巧(我不记得哪一个)。除了标签调度之外,你可以将类别与<>代码> STD::随机变量访问迭代器标签< /C> >直接使用:

使用category=typename std::iterator\u traits::iterator\u category;
如果constexpr(std::is_same_v){
调整向量大小(最后一个-第一个);
}

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

您可以使用
距离(第一,最后)
来避免检查。这可能适用于您的特定用例,但一般来说,您不能依赖“随机访问”标记来说明迭代器指向的内存是连续的。查看Microsoft的并发向量类的文档。随机访问只意味着您有迭代器理解的[]运算符。另外,如何处理反向迭代器,这是随机访问?我有一个类似的问题,我在这里发帖寻找答案:@Kentnox:谁说过记忆是连续的
last first
适用于所有随机访问迭代器,包括
std::deque::iterator
,它绝对不指向顺序内存。事实上,这正是我正在研究的g++实现(4.3.2)@Fred和
std::advance()
中使用的技术。其他选项包括(a)添加无操作功能检查(例如,
first+0;
),(b)使用显式模板专门化,或(c)使用SFINAE重载。但是,我认为这些方法都不如标记分派方法那么简单明了。如果非随机访问迭代器出错,可以使用
static\u assert
。此外,我还将考虑 STD:IsTyTraceTysLyV而不是<代码> STD::ISSAMEYVI。前者允许将来的C++版本有另一种类型的标签,也就是<代码> STD::RANDSVAIDAccess IATAPLAYTAGER 通过继承。迭代器标记已经使用继承来表示is-a关系。
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());
}
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);
}