【发布时间】:2016-08-31 15:49:26
【问题描述】:
根据this documentation of std::nth_element,RandomIt 必须满足以下约束:
-RandomIt必须满足ValueSwappable和RandomAccessIterator的要求。
-解引用的RandomIt的类型必须满足MoveAssignable和MoveConstructible的要求。
考虑到执行 std::nth_element 的算法如何工作(即它们通常只在使用 swap(*it1, *it2) 的取消引用迭代器上工作),对于 RandomIt 的 ValueSwappable,第二个要求似乎是多余的。第二个要求保证 std::swap 如果没有定义特定类型的交换将起作用。
就我而言,我想创建一个由两个迭代器组成的迭代器,其行为就像所有操作都应用于两个迭代器一样。尽管满足 ValueSwappable 约束没有问题,但我看不出如何满足 MoveConstructible 和 MoveAssignable 的要求。
这是一个这样的迭代器的例子:
template <typename ItA, typename ItB>
struct pair_iterator {
using VA = typename std::iterator_traits<ItA>::value_type;
using VB = typename std::iterator_traits<ItB>::value_type;
ItA a;
ItB b;
pair_iterator &operator++() { ++a; ++b; return *this; }
pair_iterator &operator--() { --a; --b; return *this; }
friend long operator-(const pair_iterator &iterator1, const pair_iterator &iterator2) {
return iterator1.a-iterator2.a;
}
friend pair_iterator operator+(const pair_iterator &it, size_t increment) {
return pair_iterator{it.a+increment, it.b+increment};
}
friend pair_iterator operator-(const pair_iterator &it, size_t increment) {
return pair_iterator{it.a-increment, it.b-increment};
}
bool operator==(const pair_iterator &it) const { return it.a == a && it.b == b; }
bool operator!=(const pair_iterator &it) const { return it.a != a || it.b != b; }
bool operator>=(const pair_iterator &it) const { return a >= it.a; }
bool operator<=(const pair_iterator &it) const { return a <= it.a; }
bool operator<(const pair_iterator &it) const { return a < it.a; }
bool operator>(const pair_iterator &it) const { return a > it.a; }
struct Value {
VA &a;
VB &b;
friend void swap(const Value &l, const Value &r) {
using std::swap;
swap(l.a, r.a);
swap(l.b, r.b);
}
};
Value operator*() const { return Value{*a, *b}; }
using difference_type = long;
using value_type = Value;
using pointer = void;
using reference = Value;
using iterator_category = std::random_access_iterator_tag;
};
值类型 (Value) 不可移动赋值(或以任何方式赋值),因为它包含引用。
请注意,使用 clang++ 的 std::nth_element 对这种迭代器进行测试确实有效,但如果按照我的理解相信上述要求,C++ 库的不同实现可能会破坏我的代码。
我错过了什么吗?
【问题讨论】:
-
libstdc++ 的实现肯定需要两者。
-
使用 g++4.9 进行的快速测试表明您是对的。但为什么要这样做呢?除了定义 swap() 之外,真的不需要任何东西。
-
考虑到你的迭代器甚至不是一个输入迭代器(尽管它的标签是谎言),我不明白为什么实现会向后弯腰来支持它。在 Ranges TS 之前,通常不支持代理迭代器。
-
我的(修改后的)问题是为什么需要来自迭代器的东西,而这些东西对于实现来说真的不需要?它可能会使实现更简单,但坦率地说,这不是必需的。只需要一个交换操作。添加需求会降低库的用处。