Sign in to follow this  
Erzengeldeslichtes

const_iterator to iterator...?

Recommended Posts

I have a function that takes a constant referance to a vector, and returns a const_iterator from that vector. The function that calls that function now wants to actually use that iterator, but any attempt to make it into an iterator meets with C2440, cannot convert. The only way I can find to do it is vec.begin() + (const_iterator - vec.begin()), which seems stupid. Is there a std::vector::const_iterator::const_cast or something like that?

Share this post


Link to post
Share on other sites
Unfortunately, you can't overload const_cast, or any of the *_casts for that matter. Boost's shared_ptr deals with this by defining a const_pointer_cast...

Don't think this kind of thing is available for const_iterator, and personally I'd simply advise refactoring your function into something more appropriate. If it's something complicated, you could do something like:

template < typename T >
vector< T >::const_iterator function( const vector< T > & v )
{
/* current implementation... */
}

template < typename T >
vector< T >::iterator function( vector< T > & v )
{
return v.begin() + ( function( (const vector< T > &)v ) - v.begin() );
}



Prehaps the implementation should return an index which is then used by both functions? E.g.:

template < typename T >
vector< T >::size_type function_impl( const vector< T > & v )
{
/* implementation.... */
}

template < typename T >
vector< T >::const_iterator function( const vector< T > & v )
{
return v.begin() + function_impl( v );
}

template < typename T >
vector< T >::iterator function( const vector< T > & v )
{
return v.begin() + function_impl( v );
}



I'd vote for the second version, personally.

Just a thought.

Share this post


Link to post
Share on other sites
Yeah, really you need to lose the const here. Because you are essentially requesting an interface to modify the vector, which shows intent to alter it, meaning it shouldn't be const. If it was easy to get an normal iterator from a const iterator or const container then you could easily bypass const correctness and it would be useless.

Share this post


Link to post
Share on other sites
Err, actually it's something like this:

typename std::vector<sometype>::const_iterator FindInVector(const std::vector<sometype>& v, const sometype& ToFind);
//Of course, the function is actually a highly specialized find-in-vector case
//that's only usable on specially formed vectors.


How does FindInVector tell you that I'm going to want to change the vector? Maybe I want to find the iterator at that slot and see what's ahead/behind it? What if I'm given a constant vector and want to find out what's around in it?

However, what if I do want to change it elsewhere, on a vector that ISN'T constant? The iterator refers to a vector that was constant in the child function, but now refers to the same vector that isn't constant in this function. The function finding the data didn't have permission to alter my vector, but this one does have the permission.

Is the only way to do two implementations that do the same thing? That just seems stupid. I'm not talking about getting around const-correctness. I'm talking about something like this:

std::vector v;
std::vector::const_iterator cI = FindInVector(v, 5);
std::vector::iterator i = v.const_cast_iterator(cI);


const_cast_iterator has a non-constant this pointer, so it should be able to give out a variable iterator to the same thing that the constant iterator points to. That wouldn't violate const-correctness, would it?

Mauling Monkey: Thanks for the input, I'll consider that second method.

Share this post


Link to post
Share on other sites
With a well written function, you should be able to use templates to provide both versions, but I'm not convinced that is possible with yours. As I understand it, that's how the stl algorithms work under the hood. If you supply const_iterators, you are given const_iterators.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by Conner McCloud
With a well written function, you should be able to use templates to provide both versions, but I'm not convinced that is possible with yours. As I understand it, that's how the stl algorithms work under the hood. If you supply const_iterators, you are given const_iterators.

CM


Right, they're templatized by iterator rather than container - e.g.:

template < typename iterator_t , typename value_type >
iterator_t find( iterator_t begin , iterator_t end , const & value_type value )
{
iterator_t i = begin;
while ( i != end ) {
if ( *i == value ) break;
++i;
}
return i;
}

Then, when you do:

... = find( v.begin() , v.end() , 314 );

find either returns a const_iterator if v is const, iterator if v isn't const, reverse_iterator if you used rbegin() and rend(), etc....

[Edited by - MaulingMonkey on May 29, 2005 3:43:02 AM]

Share this post


Link to post
Share on other sites
Well really why not just use one of the family of generic find/search algorithms provided by the standard library.

Quote:
Original post by MaulingMonkey
Right, they're templatized by iterator rather than container - e.g.:

template < typename iterator_t , typename value_type >
iterator_t find( iterator_t begin , iterator_t end , const & value_type value )
{
iterator_t i = begin;
while ( i != end ) {
if ( *i == value ) break;
}
return i;
}


Nice infinite loop [wink][lol].

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Well really why not just use one of the family of generic find/search algorithms provided by the standard library.

Quote:
Original post by MaulingMonkey
Right, they're templatized by iterator rather than container - e.g.:

template < typename iterator_t , typename value_type >
iterator_t find( iterator_t begin , iterator_t end , const & value_type value )
{
iterator_t i = begin;
while ( i != end ) {
if ( *i == value ) break;
}
return i;
}


Nice infinite loop [wink][lol].


*stealth edit* What infinite loop?

That's what I get for not using a for loop... *sigh*...

I really shouldn't post without caffinee.

I'm still quite confused as to why I used a while in the first place.

[Edited by - MaulingMonkey on May 29, 2005 4:31:06 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Erzengeldeslichtes
However, what if I do want to change it elsewhere, on a vector that ISN'T constant?


The usual approach is to write a second copy of the function without the const modifier.

Quote:
The iterator refers to a vector that was constant in the child function, but now refers to the same vector that isn't constant in this function. The function finding the data didn't have permission to alter my vector, but this one does have the permission.

Is the only way to do two implementations that do the same thing? That just seems stupid. I'm not talking about getting around const-correctness.


You may not be talking about const-correctness, but C++ is. :) An iterator is effectively exposing the innards of the object, so the iterator has to reflect the object it got it from, constness included. You have to take into account that it can only perform naive compile-time checks to enforce this const-correctness. If at any point it allows you to convert from const to non-const, you can break the system. Really this is the whole reason for the existence of separate const_iterator and iterator types.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this