
<Bjorn.Karlsson@readsoft.com> wrote in message news:3D8559AE95B4D611B02C0002557C6C8B01A1AB75@STH-EXCH...
From: Felipe Magno de Almeida [mailto:felipe.m.almeida@gmail.com]
What I wanted is a vector of variant<object1, object2> and I dont want object1 and object2 to be copied because it is expensive. But Im not figuring out how to do this... tried boost::ref either with no success... :/
Funny I had the same problem just a few weeks ago...
Boost.Smart_ptr (http://www.boost.org/libs/smart_ptr/smart_ptr.htm) can help: use boost::shared_ptr, which is a reference-counted smart pointer.
typedef boost::variant<object1,object2> variant_type;
std::vector<boost::shared_ptr<variant_type> > vec; boost::shared_ptr<variant_type> v(new variant_type(object1())); vec.push_back(v); // No copying of the variant
I'm afraid this is not perfect. Copy will still occur when creating the variant. The variant's constructor copies the parameter into its own storage. It's just how it works. If object1/object2 were non-copyable, then you'll see that this code doesn't compile. The solution I found starts with something similar to this, but slightly different. Instead of: typedef boost::variant<object1,object2> variant_type; std::vector<boost::shared_ptr<variant_type> > vec; I wrote: typedef boost::variant<boost::shared_ptr<object1>,boost::shared_ptr<object2> > variant_type; std::vector<variant_type> vec; Only this ensures that no copies of object1/object2 will be made. However, this solution has two problems. The first problem is that shared_ptr can be NULL, and our logic forces the shared_ptr to never be NULL. So I wrote the following class: template <typename T> class shared_ref { public: typedef T value_type; template <typename Y> explicit shared_ref(Y *a_ptr) : m_ptr(a_ptr) { } template <typename Y> explicit shared_ref(std::auto_ptr<Y> a_ptr) : m_ptr(a_ptr) { } T& get() const { T *ptr = m_ptr.get(); assert(ptr); // that's the entire essence of this class return *ptr; } operator T&() const { return get(); } T* operator->() const { return &get(); } private: boost::shared_ptr<T> m_ptr; }; This class is like shared_ptr, but it's never NULL, so I called it shared_ref. The non-null contract is validated in run-time using assert (in the get() function). (BTW, for completeness, I should have added static_cast and dynamic_cast constructors, but I had no immediate use for it, so laziness took control). Thanks to the non-null contract, I could add the implicit conversion operator to T&. The shared_ref solved this first problem, but the second problem is that that shared_ptr/shared_ref use ptr/ref const semantics (a const shared_ref<T> doesn't mean that T is const, only shared_ref<const T> does), and not value const semantics. So I wrote another class: template <typename T> class shared_obj { public: typedef T value_type; explicit shared_obj(T *a_ptr) : m_ref(a_ptr) { } explicit shared_obj(std::auto_ptr<T> a_ptr) : m_ref(a_ptr) { } shared_obj(const shared_ref<T> &a_ref) : m_ref(a_ref) { } T& get() { return m_ref.get(); } const T& get() const { return m_ref.get(); } operator T&() { return get(); } operator const T&() const { return get(); } T* operator->() { return &get(); } const T* operator->() const { return &get(); } private: shared_ref<T> m_ref; }; which gives value const semantics - a const shared_obj<T> means that T is const. Now I can write typedef boost::variant<boost::shared_obj<object1>,boost::shared_obj<object2> > variant_type; The value const semantics, plus the implicit [const] T& converstion operators allow you to use visitors as if it was a regular variant: class my_visitor : public boost::static_visitor<some_type> { some_type operator()([const] object1 &o1) { ... } some_type operator()([const] object2 &o2) { ... } }; Of course, this solution is a workaround to the fact that variant can't handle non-copyable objects. What I would *really* like to see, is variant support for non-copyable classes, something like boost::optional's in-place factory. Unfortunately, the varaint maintainers seem to not follow these lists lately... HTH, Yuval