|
Boost Users : |
From: Eric Niebler (eric_at_[hidden])
Date: 2007-07-23 18:54:24
Raider wrote:
>>
>> The const-ness of the proxy itself shouldn't matter. Only the const-ness
>> of the proxied object should matter.
>>
>
> I want const_iterator to be dereferencable to const object and iterator
> to non-cont object. Like this:
>
> class vec
> {
> public:
> vec(sv& v = global) : v_(v) {}
> typedef sv::iterator iterator;
> typedef sv::const_iterator const_iterator;
> iterator begin() const { return v_.begin(); }
> iterator end() const { return v_.end(); }
> void push_back(const string& s) const { v_.push_back(s); }
> private:
> sv& v_;
> };
It's not wrong to want that. But it is for important safety reasons that
BOOST_FOREACH treats copies of containers as const. In some of the
examples you've shown so far, you're trying to proxy a temporary object
so you can modify it. That's never going to work. Like this:
> for (xxx::iterator it(GetVector().begin(), end(GetVector().end());
> it != end; ++it) { modify(*it); }
That's not even valid C++. But even if it were and GetVector() returns a
temporary object or a proxy to a temporary object, the vector will be
destroyed before you can iterate it. The interface I chose preserves
object lifetimes and prevents inadvertent mutation of temporary objects.
Weakening its guarantees is a bad idea.
If you want the proxy to offer either a const or mutable interface *and*
you want your proxy to work with BOOST_FOREACH, you should base it on
the const-ness or mutability of the object being proxied, not the
constness of the proxy itself. Consider:
template<class Range>
struct proxy {
typedef typename range_result_iterator<Range>::type iterator;
typedef typename range_result_iterator<Range>::type const_iterator;
iterator begin() const { return boost::begin(rng_); }
iterator end() const { return boost::end(rng_); }
// etc ...
Range &rng_;
};
Now, you can have const and mutable proxied objects like:
// ok, a mutable proxy
proxy< std::vector<int> > p1;
// ok, still a mutable proxy
proxy< std::vector<int> > const p2;
// ok, a const proxy
proxy< std::vector<int> const > p3;
// still a const proxy
proxy< std::vector<int> const > const p4;
You can easily write a helper function to create the proxy object for
you that has the correct const behavior.
> This allows me make no difference does GetVector() return `vec' type
> (proxy) or `sv&' (reference to the real container):
As does the above.
> Now I found some unsteady way:
> #define BOOST_FOREACH_NO_RVALUE_DETECTION
> makes my code compile. I'll try to dig in this direction.
Don't do it. Bad things can happen if you use rvalues after you've
turned off foreach's rvalue detection.
-- Eric Niebler Boost Consulting www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net