Opened 7 years ago
Last modified 7 years ago
#12071 new Bugs
Using iterator_facade with range-v3 fails to compile
| Reported by: | Owned by: | jeffrey.hellrung | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | iterator |
| Version: | Boost 1.61.0 | Severity: | Problem |
| Keywords: | range-v3 | Cc: |
Description
The fact that postfix_increment_proxy is not DefaultConstructible and doesn't have a nested public value_type makes iterators unusable with range-v3, which check the concepts.
Example:
#include "boost/iterator/iterator_facade.hpp"
#include "range/v3/utility/iterator.hpp"
template <class V, class Category>
class TestIter
: public boost::iterator_facade<TestIter<V, Category>, V, Category, V> {
public:
using typename boost::iterator_facade<TestIter<V, Category>, V, Category,
V>::difference_type;
TestIter() : v_() {}
explicit TestIter(V v) : v_(v) {}
private:
friend class boost::iterator_core_access;
V dereference() const { return v_; }
bool equal(const TestIter& other) const { return v_ == other.v_; }
void increment() { ++v_; }
void decrement() { --v_; }
void advance(difference_type n) { v_ += n; }
difference_type distance_to(const TestIter& other) const {
return other.v_ - v_;
}
V v_;
};
using InIter = TestIter<int, std::input_iterator_tag>;
static_assert(ranges::InputIterator<InIter>(), "");
void f(InIter x) {
static_assert(ranges::Readable<decltype(x++)>(), "");
static_assert(ranges::DefaultConstructible<decltype(x++)>(), "");
}
I think static_assert(ranges::InputIterator<InIter>(), "") fails, because the two static_asserts in f() fail.
From what I've learned here:
https://github.com/ericniebler/range-v3/issues/304
it seems a good idea to fix postfix_increment_proxy to conform to these requirements. Ditto writable_postfix_increment_proxy.
Change History (2)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
| Summary: | postfix_increment_proxy is not DefaultConstructible and doesn't have a nested public value_type → Using iterator_facade with range-v3 fails to compile |
|---|
Maybe a high-level example will be helpful:
#include <iostream>
#include "third_party/boost/allowed/iterator/iterator_facade.hpp"
#include "third_party/range_v3/include/range/v3/algorithm/copy.hpp"
#include "third_party/range_v3/include/range/v3/iterator_range.hpp"
#include "third_party/range_v3/include/range/v3/utility/iterator.hpp"
template <class V, class Category>
class TestIter
: public boost::iterator_facade<TestIter<V, Category>, V, Category, V> {
public:
using typename boost::iterator_facade<TestIter<V, Category>, V, Category,
V>::difference_type;
TestIter() : v_() {}
explicit TestIter(V v) : v_(v) {}
private:
friend class boost::iterator_core_access;
V dereference() const { return v_; }
bool equal(const TestIter& other) const { return v_ == other.v_; }
void increment() { ++v_; }
void decrement() { --v_; }
void advance(difference_type n) { v_ += n; }
difference_type distance_to(const TestIter& other) const {
return other.v_ - v_;
}
V v_;
};
using InIter = TestIter<int, std::input_iterator_tag>;
template <class R>
void print(R&& r) {
ranges::copy(std::forward<R>(r), ranges::ostream_iterator<>(std::cout, ", "));
std::cout << "\n";
}
int main() {
print(ranges::make_iterator_range(InIter(1), InIter(10)));
}
Note:
See TracTickets
for help on using tickets.

Here's a simple fix, which works as long as the value type is DefaultConstructible:
--- boost/boost/iterator/iterator_facade.hpp +++ boost/boost/iterator/iterator_facade.hpp @@ -152,8 +152,9 @@ template <class Iterator> class postfix_increment_proxy { + public: typedef typename iterator_value<Iterator>::type value_type; - public: + postfix_increment_proxy() {} explicit postfix_increment_proxy(Iterator const& x) : stored_value(*x) {} @@ -178,8 +179,9 @@ template <class Iterator> class writable_postfix_increment_proxy { + public: typedef typename iterator_value<Iterator>::type value_type; - public: + writable_postfix_increment_proxy() {} explicit writable_postfix_increment_proxy(Iterator const& x) : stored_value(*x) , stored_iterator(x)To work around values which aren't DefaultConstructible, it might be necessary to wrap the
stored_valueinoptional, but the above simple fix will work for majority of cases.