Definition of proxy-based OutputIterator in terms of boost :: iterator_facade

I wrote this C ++ 17 code and expected it to work out of the box.

class putc_iterator : public boost::iterator_facade< putc_iterator, void, std::output_iterator_tag > { friend class boost::iterator_core_access; struct proxy { void operator= (char ch) { putc(ch, stdout); } }; auto dereference() const { return proxy{}; } void increment() {} bool equal(const putc_iterator&) const { return false; } }; 

I am trying to match the behavior of all the standard OutputIterators by setting my member iterator typedefs value_type and reference to void (since these types do not make sense to an iterator whose operator* does not return a link).

However, Boost complains:

 In file included from prog.cc:2: /opt/wandbox/boost-1.63.0/clang-head/include/boost/iterator/iterator_facade.hpp:333:50: error: cannot form a reference to 'void' static result_type apply(Reference const & x) ^ 

It seems that Boost is trying to hardcode the generated operator* signature as reference operator*() const . That is, boost::iterator_facade can output the correct return type operator*() by simply passing everything that dereference() was returned; but for some reason he just doesn't play.

What solution? I can not pass proxy as a template parameter to the base class, since proxy is not yet defined. I could pull the proxy into the part namespace:

 namespace detail { struct proxy { void operator= (char ch) { putc(ch, stdout); } }; } class putc_iterator : public boost::iterator_facade< putc_iterator, void, std::output_iterator_tag, detail::proxy > { friend class boost::iterator_core_access; auto dereference() const { return detail::proxy{}; } void increment() {} bool equal(const putc_iterator&) const { return false; } }; 

but it seems uncomfortable and definitely is something that "should not be necessary."

Is this a bug in iterator_facade ? Is this a non-error function? If the latter, then how should I use it to create OutputIterators?

Also, a minor nitpick: even my workaround with the part namespace is β€œwrong" in the sense that it does std::is_same_v<putc_iterator::reference, detail::proxy> when what I want (for parity with standard iterators), is std::is_same_v<putc_iterator::reference, void> .

0
c ++ boost c ++ 1z boost-iterators
Apr 18 '17 at 19:52
source share
1 answer

The Boost Iterator Facade was good at the time, but now it is deprecated because it is not very flexible (it does not work very well with auto and with r-valued links, which in principle can be created by dereferencing an r-valued iterator). I have not yet become the concept of the facade, but it could be upgraded to C ++ 11.

Also, now with C ++ 11 it's easier to write an iterator from scratch.

In any case, if you need to define reference only to match the arguments you need to pass (and if you promise not to use it), you can use void* instead of void . (Or, perhaps for consistency, use proxy& and define it outside the class).

 class putc_iterator : public boost::iterator_facade< putc_iterator, void*, std::output_iterator_tag > { friend class boost::iterator_core_access; struct proxy { void operator= (char ch) { putc(ch, stdout); } }; auto dereference() const { return proxy{}; } void increment() {} bool equal(const putc_iterator&) const { return false; } }; 
0
Apr 21 '17 at 8:26
source share



All Articles