Reputation: 4255
There is the following class B derived from std::vector
class B: public std::vector <unsigned int>
{
public:
B() : std::vector <unsigned int> ( 0 ) {}
};
and a class A witten as follows:
class A
{
private:
B b;
double x;
public:
B & getB () {return b;}
B const & getB() const {return b;}
bool operator() ( const A & a ) const
{
return a < a.x;
}
};
Why it is impossible to return a refererence to the variable b of some object A stored in std::list from its iterator (and how to do that)?
int main ()
{
std::set <A > alist;
std::set <A> ::iterator i_alist = alist.begin();
for (; i_alist != alist.end(); i_list++)
{
B &il = (*i_alist).getB(); //Compiler error
B &il2 = i_alist->getB(); //Compiler error
il.push_back(10); //Modify il and concurrently B
}
}
Compiler error:
Error 1 error C2440: 'initializing' : cannot convert from 'const B' to 'B &' d:\test.cpp
Thanks for your help...
Edit question:
The possible solution using const_cast :
B &il2 = const_cast <B&> ( i_alist->getB() );
Upvotes: 1
Views: 1286
Reputation: 320421
This has very little to do with std::vector
and everything to do with std::set
. You store your objects in a std::set
. Elements of std::set
are not modifiable from the outside. Once you inserted an element into a set, you cannot change it.
For this reason, std::set::iterator
might (and will) evaluate to a constant object, even if it is not a const_iterator
(the language specification actually allows std::set::iterator
and std::set::const_iterator
to refer to the same type, but does not require it). I.e. in your example *i_list
is a const-qualified object of type const A
. The compiler will call the const
version of getB
, which returns const B &
. You are apparently hoping to break through that constness, expecting the non-const version of getB
to be called.
There's no way around it, unless you decide to use some sort of hack (const_cast
etc.) to remove the constness from the set element and thus make the compiler to call non-const version of getB
.
The const_cast
-based hack-solution would look as
B &il = const_cast<A &>(*i_alist).getB();
or you can remove the constness later, from the returned B
reference
B &il = const_cast<B &>((*i_alist).getB());
B &il2 = const_cast<B &>(i_alist->getB());
Upvotes: 7
Reputation: 24596
There are some things that look weird about your example:
std::vector
. It's not designed for that use. And there normally is no reason to do so, except laziness, i.e. to avoid some typing.A::operator()
for? Looks like some strange way to provide a Comparator for the std::set
you are using. Normally you don't alter a class just because you stuff it into a std::set
somewhere. If you really want to be able to compare your A's (generally, not just for the set), then write a proper free bool operator<(A const&, A const&);
If it's just for the set, write a custom Comparator in the place where you use the set. (That comparator should not need to access A's privates)A::x
used for? Only for comparison or even only for the comparison inside the set? If it's just that, consider to use a std::map<double, A>
or even a std::map<double, B>
where you put your x as the keys and the actual objects as the values. You see, there are a lot of open questions I ask, and maybe the solution (using a map) does not even fit your problem. That is because you did not show us the real code you have but only some example with meaningless names. So we only see what you are trying to do, not what you actually want to achieve with your code.
PS: maybe you don't even need an ordered container in the first place, it could suffice to stuff all the objects into a std::vector
and then std::sort
it. Depends on the kind of objects you really have (the A's of your example are cheap to copy/swap) and of the ways you use the container - how the insertions are interleaved with the loops and so on.
Upvotes: 0