Boost logo

Boost Users :

From: Yuval Ronen (ronen_yuval_at_[hidden])
Date: 2007-03-20 06:06:58


Dizzy wrote:
> However, initial testing for boost::variant shows that that there is no
> compile time check on the types allowed to instantiate boost::get on a
> variant, example:
>
> struct A {}; struct B {}; struct C{};
>
> int main()
> {
> boost::variant v<A, B> v;
> boost::get<C>(v);
> }
>
> Compiles fine (gcc 4.1.1, boost 1.33.1) but errors at runtime throwing a
> bad_get exception from get. It seems to me that the get<> on variant somehow
> works for any type not checking if the type parameter for get matches one in
> the type sequence of the given variant.
>
> Maybe I miss something but shouldn't get on variant have a compile time type
> check ? (this would catch at compile time common errors for variant use cases
> I think)

I agree.
It might be true that the version without compile-time has its just
usages, but the version with the compile-time check is much more useful.
So I found myself adding the following functions:

template <typename T, typename Variant>
void assert_variant_has_type(const Variant &)
{
        BOOST_MPL_ASSERT((mpl::contains<typename Variant::types, T>));
}

template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
inline typename add_pointer<U>::type get_exact(
        boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
        BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
{
        assert_variant_has_type<U>(*operand);
        typedef typename add_pointer<U>::type U_ptr;
        if (!operand) return static_cast<U_ptr>(0);
        if (operand->type() != typeid(U)) return static_cast<U_ptr>(0);

        detail::variant::get_visitor<U> v;
        return operand->apply_visitor(v);
}

template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
inline typename add_pointer<const U>::type get_exact(
        const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
        BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
{
        assert_variant_has_type<U>(*operand);
        typedef typename add_pointer<const U>::type U_ptr;
        if (!operand) return static_cast<U_ptr>(0);
        if (operand->type() != typeid(U)) return static_cast<U_ptr>(0);

        detail::variant::get_visitor<const U> v;
        return operand->apply_visitor(v);
}

template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
inline typename add_reference<U>::type get_exact(
        boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
        BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
{
        typedef typename add_pointer<U>::type U_ptr;
        U_ptr result = get_exact<U>(&operand);

        if (!result)
                throw bad_get();
        return *result;
}

template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
inline typename add_reference<const U>::type get_exact(
        const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
        BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U))
{
        typedef typename add_pointer<const U>::type U_ptr;
        U_ptr result = get_exact<const U>(&operand);

        if (!result)
                throw bad_get();
        return *result;
}


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