// -*- mode:C++; tab-width:8; c-basic-offset:4; indent-tabs-mode:t -*- // vim: ts=8 sw=4 smarttab /* * Copied from: * https://github.com/exclipy/inline_variant_visitor/blob/master/inline_variant.hpp */ #ifndef INLINE_VARIANT_H #define INLINE_VARIANT_H #include #include #include #include #include #include #include "function_signature.h" namespace detail { // A metafunction class for getting the argument type from a unary function or functor type struct function_arg_extractor { // Function is either a function type like void(int const&), or a functor - eg. a class with void operator(int) // Sets type to the argument type with the constness and referenceness stripped (eg. int) template struct apply { private: typedef typename boost::remove_const< typename boost::remove_reference::type >::type bare_type; typedef typename signature_of::type normalized_function_type; typedef typename boost::function_types::function_arity::type arity; typedef typename boost::function_types::parameter_types::type parameter_types; typedef typename boost::function_types::result_type::type result_type; BOOST_STATIC_ASSERT_MSG((arity::value == 1), "make_visitor called with a non-unary function"); typedef typename boost::mpl::front::type parameter_type; public: typedef typename boost::remove_const< typename boost::remove_reference::type >::type type; }; }; struct make_pair { template struct apply { typedef boost::mpl::pair type; }; }; // A metafunction class that asserts the second argument is in Allowed, and returns void template struct check_in { template struct apply { private: BOOST_STATIC_ASSERT_MSG((boost::mpl::contains::type>::value), "make_visitor called with spurious handler functions"); public: typedef void type; }; }; template struct as_map { private: struct insert_helper { template struct apply { typedef typename boost::mpl::insert< M, P>::type type; }; }; public: typedef typename boost::mpl::fold, insert_helper>::type type; }; // A functor template suitable for passing into apply_visitor. The constructor accepts the list of handler functions, // which are then exposed through a set of operator()s template struct generic_visitor : boost::static_visitor, boost::noncopyable { private: typedef generic_visitor type; // Compute the function_map type typedef boost::mpl::vector function_types; typedef typename boost::mpl::transform::type arg_types; typedef typename boost::mpl::transform< arg_types, boost::mpl::range_c::value>, make_pair >::type pair_list; typedef typename as_map::type fmap; // Check that the argument types are unique BOOST_STATIC_ASSERT_MSG((boost::mpl::size::value == boost::mpl::size::value), "make_visitor called with non-unique argument types for handler functions"); // Check that there aren't any argument types not in the variant types typedef typename boost::mpl::fold >::type dummy; boost::fusion::vector fvec; template Result apply_helper(const T& object, boost::mpl::true_) const { typedef typename boost::mpl::at::type Ind; return boost::fusion::at(fvec)(object); } template Result apply_helper(const T& object, boost::mpl::false_) const { return Result(); } BOOST_MOVABLE_BUT_NOT_COPYABLE(generic_visitor) public: generic_visitor(BOOST_RV_REF(type) other) : fvec(boost::move(other.fvec)) { } generic_visitor(Functions&&... functions) : fvec(std::forward(functions)...) { } template Result operator()(const T& object) const { typedef typename boost::mpl::has_key::type correct_key; BOOST_STATIC_ASSERT_MSG(correct_key::value, "make_visitor called without specifying handlers for all required types"); return apply_helper(object, correct_key()); } }; // A metafunction class for getting the return type of a function struct function_return_extractor { template struct apply : boost::function_types::result_type::type> { }; }; // A metafunction class that asserts the two arguments are the same and returns the first one struct check_same { template struct apply { private: BOOST_STATIC_ASSERT_MSG((boost::is_same::value), "make_visitor called with functions of differing return types"); public: typedef Type1 type; }; }; // A metafunction for getting the required generic_visitor type for the set of Functions template struct get_generic_visitor { private: typedef boost::mpl::vector function_types; typedef typename boost::mpl::transform< function_types, boost::remove_const< boost::remove_reference > >::type bare_function_types; typedef typename boost::mpl::transform::type return_types; public: // Set result_type to the return type of the first function typedef typename boost::mpl::front::type result_type; typedef generic_visitor type; private: // Assert that every return type is the same as the first one typedef typename boost::mpl::fold::type dummy; }; // Accepts a set of functions and returns an object suitable for apply_visitor template auto make_visitor(BOOST_RV_REF(Functions)... functions) -> typename detail::get_generic_visitor::type { return typename detail::get_generic_visitor::type(boost::forward(functions)...); } } template auto match(Variant const& variant, BOOST_RV_REF(Functions)... functions) -> typename detail::get_generic_visitor::result_type { return boost::apply_visitor(detail::make_visitor( boost::forward(functions)...), variant); } #endif