[iterator facade] Why is dereference const?

In iterator_facade.hpp: reference operator*() const Why the const? I am writing function_input_iterator (again), using iterator_facade. The functor used as a generator may not be const - it might well have state. Therefore, dereference changes the state, and so isn't const.

"Neal Becker" <ndbecker2@verizon.net> wrote in message news:c7uljb$etk$1@sea.gmane.org...
In iterator_facade.hpp:
reference operator*() const
Why the const?
So you could dereference const iterators
I am writing function_input_iterator (again), using iterator_facade. The functor used as a generator may not be const - it might well have state. Therefore, dereference changes the state, and so isn't const.
Make'em mutable. Dereference is 'naturally' const operation. So special cases should be marked as special. Gennadiy.

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
"Neal Becker" <ndbecker2@verizon.net> wrote in message news:c7uljb$etk$1@sea.gmane.org...
In iterator_facade.hpp:
reference operator*() const
Why the const?
So you could dereference const iterators
I suppose we could provide a non-const overload, but that doesn't sound like the right tool for this particular job.
I am writing function_input_iterator (again), using iterator_facade. The functor used as a generator may not be const - it might well have state. Therefore, dereference changes the state, and so isn't const.
Make'em mutable. Dereference is 'naturally' const operation. So special cases should be marked as special.
I think that's the right thing to do, but not quite the right explanation. The reason to make the function object mutable is that changes to the function object don't affect the "logical constness" of the iterator. Any state in the function object only changes "once per position" when it's embedded in the iterator, so that operator++ is the effectively non-const operation. The following input iterator requirements guarantee that operator* isn't allowed to advance the iterator: expression type semantics,pre/post-conditions ---------- ---- ----------------------------- *a convertible to T pre: a is dereferenceable. If a==b and (a,b) is in the domain of == then *a is equivalent to *b. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Thanks for the advice. I think I have it now. Problem: A function F accepts a pair of stl-style iterators as input. A nullary functor G can generate an output. Arrange for F to call G n times without storing to an intermediate sequence. Example: G is a random number generator. I wonder if there is a more elegant approach? Here is what I came up with. It is almost perfect, there seems to be 1 extra call to G() that I haven't accounted for, but this may or may not be important.

"Neal D. Becker" <ndbecker2@verizon.net> writes:
I wonder if there is a more elegant approach?
Yeah: cache a value in the iterator with boost::optional<value_type>. Put a new value in the cache when the iterator is incremented. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
"Neal D. Becker" <ndbecker2@verizon.net> writes:
I wonder if there is a more elegant approach?
Yeah: cache a value in the iterator with boost::optional<value_type>. Put a new value in the cache when the iterator is incremented.
Good suggestion! I'll post the modified code if anyone is interested. Actually, though, I was wondering if anyone had a more elegant approach in a more general sense, to the problem of transforming some kind of source into a sequence. Possibly "range" could be useful, but I don't know.

Neal D. Becker wrote:
Thanks for the advice. I think I have it now.
Problem:
A function F accepts a pair of stl-style iterators as input. A nullary functor G can generate an output. Arrange for F to call G n times without storing to an intermediate sequence.
Example: G is a random number generator.
I wonder if there is a more elegant approach?
I have a couple of questions 1. Is this really forward_traversal_iterator? E.g. if your function extracts data from stream, then you can't store copies of iterators and make a second pass over the data. 2. Why did you declared 'advance'. IIRC, this is not required from forward iterators. As for improving this, I also have two ideas: 1. Some time ago I've created an utility class for creating input iterators, called "eof_iterator". Reimplementing function_input_iterator with it yeilds somewhat smaller code, see: http://zigzag.cs.msu.su:7813/iterators/function_input_iterator2.hpp the eof iterator itself is at: http://zigzag.cs.msu.su:7813/iterators/eof_iterator.hpp There are some drawbacks, though: the size of iterator will be bigger. 2. It's possible to create iterator which just calls functional object (without counting). As separate "until_iterator" would take any iterator and a functional object and iterate until the functional object returns true. So, your iterator will be implemented like: typedef function_input_iterator<SomeFunc> it; class CountTo { ... }; typedef until_iterator<it, CountTo> uit; copy(uit(it(some_func), CountTo(10)), uit(), ........) I actually believe that such until_iterator can be rather usefull sometimes. - Volodya

Vladimir Prus wrote:
Neal D. Becker wrote:
Thanks for the advice. I think I have it now.
Problem:
A function F accepts a pair of stl-style iterators as input. A nullary functor G can generate an output. Arrange for F to call G n times without storing to an intermediate sequence.
Example: G is a random number generator.
I wonder if there is a more elegant approach?
As for improving this, I also have two ideas:
1. Some time ago I've created an utility class for creating input iterators, called "eof_iterator". Reimplementing function_input_iterator with it yeilds somewhat smaller code, see:
http://zigzag.cs.msu.su:7813/iterators/function_input_iterator2.hpp
the eof iterator itself is at:
I love it! Just one small improvement: eof_iterator add parameter: template<class Derived, class ValueType, class traversal_type=forward_traversal_tag> class eof_iterator : public iterator_facade<Derived, const ValueType, traversal_type> And change function_input_iterator: template<class FUNC> class function_input_iterator2 : public boost::eof_iterator< function_input_iterator2<FUNC>, typename boost::remove_reference<FUNC>::type::result_type, boost::single_pass_traversal_tag

Neal D. Becker wrote:
I love it! Just one small improvement:
eof_iterator add parameter:
template<class Derived, class ValueType, class traversal_type=forward_traversal_tag> class eof_iterator : public iterator_facade<Derived, const ValueType, traversal_type>
Ok, I guess one can create forward_iterator with eof_iterator, so it makes sense. - Volodya

Interesting. I have very similar design that I call input_iterator facade. The only difference is that I do not have found_eof() interface. Instead I use result value of get method. So increment looks like: void increment() { m_valid = static_cast<Derived&>(*this).get(); } Unfortunately new design does not allow you to call get in constructor. I even thought to present version that uses mixed old/new design with input_iterator_facde accepting policy that implements get method. Anyway why don't we add something like this in iterator library. I found it quite usefull (tokeen_iterator could use it for example) Gennadiy.

Gennadiy Rozental wrote:
Interesting. I have very similar design that I call input_iterator facade. The only difference is that I do not have found_eof() interface. Instead I use result value of get method. So increment looks like:
void increment() { m_valid = static_cast<Derived&>(*this).get(); }
Interesting... and I presume 'equal' works by comparing 'm_valid'?
Unfortunately new design does not allow you to call get in constructor.
Why? Because constructor of your input_iterator_facace is run before constructor of derived class? But maybe resposibility of calling 'get' should be on derived class, at least that's how my eof_iterator works.
I even thought to present version that uses mixed old/new design with input_iterator_facde accepting policy that implements get method.
I'm not yet sure what are advantanges/disadvantages. I see some other way for improvement: maybe in some cases storing "m_at_eof"/"m_valid" flag is not necessary and derived iterator can provide method "at_eof". That would save some space.
Anyway why don't we add something like this in iterator library. I found it quite usefull (tokeen_iterator could use it for example)
I wonder what iterator library authors think about it? Since eof_iterator is used by the program_options library it need to exist in CVS somewhere... is it OK to put in in "boost/iterator" as opposed to "boost/program_options"? - Volodya

Neal D. Becker wrote:
Thanks for the advice. I think I have it now.
Problem:
A function F accepts a pair of stl-style iterators as input. A nullary functor G can generate an output. Arrange for F to call G n times without storing to an intermediate sequence.
Example: G is a random number generator.
I wonder if there is a more elegant approach? Here is what I came up with.
Yes, there is. rtl (Range Templates Library) has a generate_iterator. You have a generator, and a stopper. From these, you create an input iterator sequence. The stopper tells you when you've reached end. For instance: // input iterator sequence - 20 fibonacci numbers generated(fibonacci(), gen_n(20)) // input iterator sequence - fibonacci numbers up to 200 generated(fibonacci(), gen_upto(200)) You can use it like this: rng::copy( generated(fibonacci(), gen_upto(200)), std::ostream_iterator<int>(std::cout," ")); The rtl (and the generate* examples) can be found at: www.torjo.com/code/for_boost.zip Best, John -- John Torjo Freelancer -- john@torjo.com -- http://www.torjo.com/logview/ - viewing/filtering logs is just too easy!

John Torjo wrote:
Neal D. Becker wrote:
Thanks for the advice. I think I have it now.
Problem:
A function F accepts a pair of stl-style iterators as input. A nullary functor G can generate an output. Arrange for F to call G n times without storing to an intermediate sequence.
Example: G is a random number generator.
I wonder if there is a more elegant approach? Here is what I came up with.
Yes, there is. rtl (Range Templates Library) has a generate_iterator.
You have a generator, and a stopper. From these, you create an input iterator sequence. The stopper tells you when you've reached end.
For instance: // input iterator sequence - 20 fibonacci numbers generated(fibonacci(), gen_n(20))
// input iterator sequence - fibonacci numbers up to 200 generated(fibonacci(), gen_upto(200))
You can use it like this: rng::copy( generated(fibonacci(), gen_upto(200)), std::ostream_iterator<int>(std::cout," "));
The rtl (and the generate* examples) can be found at: www.torjo.com/code/for_boost.zip
The RTL approach looks very interesting. There is a lot to digest here. What is the state of maturity of this code? Would you consider it ready for use?
participants (6)
-
David Abrahams
-
Gennadiy Rozental
-
John Torjo
-
Neal Becker
-
Neal D. Becker
-
Vladimir Prus