Topic: Const_iterators
Author: Jean-Louis Leroy <jll@skynet.be>
Date: 1998/01/07 Raw View
In article <fxt3ejrbzur.fsf@isolde.mti.sgi.com>, Matt Austern wrote:
> So what this means is that there is an implicit conversion from
> reverse_iterator<T> to reverse_iterator<U> if and only if there is an
> implicit conversion from T to U.
>
> It seems to me that this is just about right.
Besides, this is the behavior you get for iterators that happen to be
straight pointers, typically vector<T>::iterator.
Jean-Louis Leroy
http://ourworld.compuserve.com/homepages/jl_leroy
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Jean-Louis Leroy <jll@skynet.be>
Date: 1997/12/15 Raw View
In article <66t936$dq6@marianna.psu.edu>, Oleg Zabluda wrote:
> int main()
> {
> vector<int> v;
> vector<int>::const_iterator i = v.begin(); // [1]
> vector<int>::const_reverse_iterator j = v.rbegin(); // [2]
>
> return 0;
> }
>
> On your compiler [1] is likely to compile (by sheer luck, and
> it's non-standard and non-portable), while [2] is unlikely
> to compile at all.
A simpler (and more annoying) example is the absence of conversion from
set::itrerator to set::const_iterator. This makes it really hard to
maintain code like:
class X
{
set<Y> y;
void f() const
{
set<Y>::const_iterator iter = y.begin();
// ... don't modify set
}
};
// later, f() is not const any longer:
void f()
{
set<Y>::const_iterator iter = y.begin(); // bad karma!
// ... still don't modify set
}
Also, it makes the kind of iterator depend on what you obtain it from,
not on what you intend to do with (modify collection or not).
Incidentally, Plaugher's STL (VC5 version) allows such conversion,
because both iterators are typedefs to a rb_tree::const_iterator. Kai
C++ disallows the conversion. As it happens, we're developing on NT/VC5
and delivering on AIX/Kai. Needless to say, each time we port we need to
fix iterators conversions that slipped past the coder's attention.
http://ourworld.compuserve.com/homepages/jl_leroy
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Matt Austern <austern@sgi.com>
Date: 1997/12/15 Raw View
Oleg Zabluda <zabluda@math.psu.edu> writes:
> Some time ago I complained that the DWP didn't mandate an existance
> of a conversion of some sort from iterators to corresponding
> const_iterators:
>
> #include <vector>
>
> int main()
> {
> vector<int> v;
> vector<int>::const_iterator i = v.begin(); // [1]
> vector<int>::const_reverse_iterator j = v.rbegin(); // [2]
>
> return 0;
> }
>
> On your compiler [1] is likely to compile (by sheer luck, and
> it's non-standard and non-portable), while [2] is unlikely
> to compile at all.
>
> My question is: was it fixed, and if not, why not?
For containers, actually, there is (and there always has been) a
conversion from Container::iterator to Container::const_iterator. The
requirement is a little hard to find, but it's there. It's in the
fourth line of Table 65 (Container Requirements), in clause 23.1. The
note for X::iterator says "convertible to X::const_iterator".
Until very recently, the point about conversion from reverse_iterator
to const_reverse_iterator was quite valid; it was a real problem.
However, the standardization committee did fix that problem. Again,
the fix isn't immediately obvious, but it's there. Table 66 says
exactly what types X::reverse_iterator and X::const_reverse_iterator
are: they are, respectively, std::reverse_iterator<X::iterator> and
std::reverse_iterator<X::const_iterator>. So the question really
comes down to this: if I1 and I2 are iterators, and I1 is convertible
to I2, does it follow that std::reverse_iterator<I1> is convertible to
std::reverse_iterator<I2>?
The answer is yes. If you turn to section 24.4.1, where
reverse_iterator is described, you'll see that it has a member
template "generalized copy constructor" that provides that conversion.
It's in section 24.4.1.3.1, and its signature is
template <class T> template <class U>
reverse_iterator<T>::reverse_iterator(const reverse_iterator<U>&).
The generalized copy construtor was added to the standard very
recently. It has, however, been implemented and tested, and it does
solve this problem.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/12/16 Raw View
Matt Austern <austern@sgi.com> wrote:
: Oleg Zabluda <zabluda@math.psu.edu> writes:
: > Some time ago I complained that the DWP didn't mandate an existance
: > of a conversion of some sort from iterators to corresponding
: > const_iterators:
: >
: > #include <vector>
: >
: > int main()
: > {
: > vector<int> v;
: > vector<int>::const_iterator i = v.begin(); // [1]
: > vector<int>::const_reverse_iterator j = v.rbegin(); // [2]
: >
: > return 0;
: > }
: >
: > On your compiler [1] is likely to compile (by sheer luck, and
: > it's non-standard and non-portable), while [2] is unlikely
: > to compile at all.
: >
: > My question is: was it fixed, and if not, why not?
: For containers, actually, there is (and there always has been) a
: conversion from Container::iterator to Container::const_iterator. The
: requirement is a little hard to find, but it's there. It's in the
: fourth line of Table 65 (Container Requirements), in clause 23.1. The
: note for X::iterator says "convertible to X::const_iterator".
In my copy of DWP (Dec 2, 1996) this table has number 66, and no such
comment is there. Is the copy you are refering to publicly available?
: Until very recently, the point about conversion from reverse_iterator
: to const_reverse_iterator was quite valid; it was a real problem.
: However, the standardization committee did fix that problem. Again,
: the fix isn't immediately obvious, but it's there. Table 66 says
: exactly what types X::reverse_iterator and X::const_reverse_iterator
: are: they are, respectively, std::reverse_iterator<X::iterator> and
: std::reverse_iterator<X::const_iterator>. So the question really
: comes down to this: if I1 and I2 are iterators, and I1 is convertible
: to I2, does it follow that std::reverse_iterator<I1> is convertible to
: std::reverse_iterator<I2>?
: The answer is yes. If you turn to section 24.4.1, where
: reverse_iterator is described, you'll see that it has a member
: template "generalized copy constructor" that provides that conversion.
: It's in section 24.4.1.3.1, and its signature is
: template <class T> template <class U>
: reverse_iterator<T>::reverse_iterator(const reverse_iterator<U>&).
Great. (My copy doesn't have it). I have a question though. This
"generalized copy constructor" seems to be too general.
We don't want to be able to (implicitly!) convert reverse_iterator<T> to
reverse_iterator<U>. We only want to be able to convert
reverse_iterator<X::iterator> to reverse_iterator<X::const_iterator>.
Shouldn't we require that only a partial specialization of the
above, and nothing else, be defined:
template<class X>
reverse_iterator<typename X::const_iterator>::
reverse_iterator(const reverse_iterator<typename X::iterator>&)
What exactly is the wording of 24.4.1.3.1 in this respect?
: The generalized copy construtor was added to the standard very
: recently. It has, however, been implemented and tested, and it does
: solve this problem.
Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Matt Austern <austern@sgi.com>
Date: 1997/12/17 Raw View
Oleg Zabluda <zabluda@math.psu.edu> writes:
> : For containers, actually, there is (and there always has been) a
> : conversion from Container::iterator to Container::const_iterator. The
> : requirement is a little hard to find, but it's there. It's in the
> : fourth line of Table 65 (Container Requirements), in clause 23.1. The
> : note for X::iterator says "convertible to X::const_iterator".
>
> In my copy of DWP (Dec 2, 1996) this table has number 66, and no such
> comment is there. Is the copy you are refering to publicly available?
Oops, sorry. I guess I was wrong in thinking that guarantee was
always there; it was in the original Stepanov-Lee documentation,
anyway, and it was also there in the code.
The WP that I'm quoting from is dated 25 November 1997, and there will
be no substantive changes between that copy of the WP and the version
that will be distributed as the FDIS. (I think that the project
editor might have to make some layout and formatting changes, but I'm
not sure of that.)
> Great. (My copy doesn't have it). I have a question though. This
> "generalized copy constructor" seems to be too general.
> We don't want to be able to (implicitly!) convert reverse_iterator<T> to
> reverse_iterator<U>. We only want to be able to convert
> reverse_iterator<X::iterator> to reverse_iterator<X::const_iterator>.
The signature of the constructor is
template <class U> reverse_iterator(const reverse_iterator<U> &u);,
and what the standard says is "Initializes current with u.current."
So what this means is that there is an implicit conversion from
reverse_iterator<T> to reverse_iterator<U> if and only if there is an
implicit conversion from T to U.
It seems to me that this is just about right. Implicit conversions
from one iterator type to another are a pretty rare thing, and if you
do define two iterators so that one is implicitly convertible to
another then you probably do want that to apply to the reverse
iterator versions as well.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/12/13 Raw View
Some time ago I complained that the DWP didn't mandate an existance
of a conversion of some sort from iterators to corresponding
const_iterators:
#include <vector>
int main()
{
vector<int> v;
vector<int>::const_iterator i = v.begin(); // [1]
vector<int>::const_reverse_iterator j = v.rbegin(); // [2]
return 0;
}
On your compiler [1] is likely to compile (by sheer luck, and
it's non-standard and non-portable), while [2] is unlikely
to compile at all.
My question is: was it fixed, and if not, why not?
Note that the vector is defined as
vector< class T, class Allocator = allocator<T> >,
and the way the standard allocator is defined, there are already
standard conversions from allocator::pointer and allocator::reference
to corresponding const types, which helps.
Now two workarounds:
typedef vector<int> T;
(1) T::const_reverse_iterator i = const_cast<T const&>(v).rbegin();
(2) typedef T::const_reverse_iterator(T::*rbeginc_t)() const;
rbeginc_t const rbeginc = &T::rbegin;
T::const_reverse_iterator j = (v.*rbeginc)();
(2) is longer, but the advantage is that the first two lines can
be put in a header, and then *rbeginc() can applied
to different vectors without a need to apply explicit casts.
Both (1) and (2) can be templatized, of course.
Question: is there any particular reason why the following is not
allowed:
vector<int>::const_reverse_iterator j = v.rbegin() const;
Related question: why there are no const_forward_iterator's,
const_bidirectional_iterator's, and so on, with appropriate conversions
from non-const variants, and why not use const_*_iterators as arguments in
the algorithms they are appropriate for.
Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]