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; }