According to this documentation of std::nth_element, the RandomIt must satisfy the following constraints:
-RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.
-The type of dereferenced RandomIt must meet the requirements of MoveAssignable and MoveConstructible.
It seems that the second requirement is redundant with the ValueSwappable of RandomIt, given how algorithms doing std::nth_element work (i.e. they typically only work on the dereferenced iterator with a swap(*it1, *it2) ). The second requirement guarantees that std::swap will work if there is no type-specific swap defined.
In my case, I want to create an iterator that is composed of two iterators and behaves as if all the operations were applied to both iterators. Though I have no trouble satisfying the ValueSwappable constraint, I do not see how I can satisfy the MoveConstructible and MoveAssignable requirements as well for my purpose.
Here is an example of such an iterator:
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; }
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;
};
The value type (Value) is not move assignable (or assignable in any way for that matter) because it contains references.
Note that a test of such an iterator with std::nth_element of clang++ does work, but if one is to believe the above requirements as I understand them, a different implementation of the C++ library may break my code.
Am I missing something?
Aucun commentaire:
Enregistrer un commentaire