根据this documentation of std::nth_element,RandomIt必须满足以下约束条件:
-RandomIt必须满足ValueSwappable和RandomAccessIterator的要求。
- 解除引用的RandomIt类型必须满足MoveAssignable和MoveConstructible的要求。
似乎第二个要求与RandomIt的ValueSwappable是多余的,考虑到std :: nth_element的算法是如何工作的(即它们通常仅在带有交换的解除引用的迭代器上工作(* it1,* it2))。第二个要求保证如果没有定义特定于类型的交换,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;
};
值类型(值)不可移动(也可以任何方式分配),因为它包含引用。
请注意,使用clang ++的std :: nth_element对这样的迭代器进行测试确实有效,但如果按照我的理解相信上述要求,则C ++库的不同实现可能会破坏我的代码。
我错过了什么吗?
答案 0 :(得分:0)
以上是与libstdc ++一起使用的上述迭代器的修改版本。
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; }
struct ValueCopy {
VA a;
VB b;
};
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=(Value&&v) {
a = v.a;
b = v.b;
return *this;
}
Value &operator=(const ValueCopy &v) {
a = v.a;
b = v.b;
return *this;
}
operator ValueCopy() const { return ValueCopy{a,b}; }
};
Value operator*() { return {*a, *b}; }
using difference_type = long;
using value_type = ValueCopy;
using pointer = void;
using reference = Value;
using iterator_category = std::random_access_iterator_tag;
};
这里的技巧是定义value_type和reference,以便* it1 = * it2;有效,但值v = * it; * it2 = v; 我仍然不确定这是否会一直有效。
PS:澄清为什么我想要一个&#34;代理迭代器&#34;,这是因为我想对一个向量执行nth_element操作,同时能够构建一个旧索引的向量数据向量。我知道这可以通过在索引向量上使用比较运算符来完成,但经验表明这种方法比同时对数据排序要慢很多,因为如果索引被移动会发生缓存垃圾但不是数据。