[variant]compile-time-checked boost::get<T>?

Hello, I just replaced our own union implementation by boost::variant and was surprised that boost::get<T> does not compile-time check T. IMHO, boost::get<T> should only compile if T is a possible member of the variant. We implemented this with an enable_if without much difficulty. As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee. Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

Arno Schödl wrote:
As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
Actually, it should work with all types that are convertible from any of the types of the variant.

Mathias Gaunard wrote:
Arno Schödl wrote:
As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
Actually, it should work with all types that are convertible from any of the types of the variant.
Would it work for a type that is convertible from two or more of the types of the variant? Joe Gottman

AMDG Joe Gottman wrote:
Mathias Gaunard wrote:
Arno Schödl wrote:
As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
Actually, it should work with all types that are convertible from any of the types of the variant.
Would it work for a type that is convertible from two or more of the types of the variant?
It had better not compile in that case, unless one of the types is a better match than the rest. How about implementing get along these lines (untested): template<class T, class Variant, class Base> struct get_impl : Base { operator typename mpl::at_c<typename Variant::types>::type&() const { return(get<T>(*this->variant)); } }; template<class Variant> struct get_impl_base { Variant* variant; }; template<class T, class Variant> T checked_get(const Variant& variant) { typename mpl::fold<typename Variant::types, get_impl_base<Variant>, get_impl<_1, Variant, _2> >::type impl; impl.variant = &variant; return T(impl); } In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Joe Gottman wrote:
Mathias Gaunard wrote:
Arno Schödl wrote:
As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
Actually, it should work with all types that are convertible from any of the types of the variant.
Would it work for a type that is convertible from two or more of the types of the variant?
It had better not compile in that case, unless one of the types is a better match than the rest.
What's so dangerous about it compiling in that case? What's wrong with having get<S> convert the actual underlying object of the current Variant to S& (or possibly const S &) if possible, and throwing an exception otherwise? Joe Gottman

Actually, it should work with all types that are convertible from any of the types of the variant.
Would it work for a type that is convertible from two or more of the types of the variant? It had better not compile in that case, unless one of the types is a better match than the rest.
I think that making this work would actually be desirable. For example, it would allow storing a base class together its derived class in the same variant. Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
Actually, it should work with all types that are convertible from any of the types of the variant.
Arguably, only conversion to an L-value are o.k., do you agree? But boost::is_convertible<T const&, S const&> compiles on MSVC9 even if the conversion is to an R-value: class S {}; class T { public: operator S() const{ return S(); // returns a value! } }; // but cast to const reference works T t; static_cast<S const&>(t); // and is_convertible says it does BOOST_STATIC_ASSERT( boost::is_convertible<T const& BOOST_PP_COMMA() S const&>::value ); I think we must require boost::is_convertible<T &, S &> and also make sure static_cast<S &>(T) is actually used. The cast inside boost::get for a constant variant would then look like this: static_cast<S const&>( static_cast<S &>( const_cast<T &>( t ) ) ); I am not sure whether this always does the intended thing. The problem to ensure that a cast is to L-value seems quite general, so maybe someone knows a standard solution? P.S. Did I get the L-value vs. R-value terminology right :-) ? -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

on Wed Dec 10 2008, Arno Schödl <aschoedl-AT-think-cell.com> wrote:
Hello,
I just replaced our own union implementation by boost::variant and was surprised that boost::get<T> does not compile-time check T. IMHO, boost::get<T> should only compile if T is a possible member of the variant. We implemented this with an enable_if without much difficulty.
As a further extension, boost::get<S> where S is a base class of a T contained in the variant, should also work. I believe this would also be implementable with enable_if/disable_if, but we have not done it, so no guarantee.
I agree with you, FWIW -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (5)
-
Arno Schödl
-
David Abrahams
-
Joe Gottman
-
Mathias Gaunard
-
Steven Watanabe