
On Mon, Jan 16, 2012 at 5:34 PM, Nathan Ridge <zeratul976@hotmail.com> wrote:
This can be implemented using a suitable function_type that returns the function type result_type (arg1_type, ...) from a function type, function pointer, function reference, or from a functor which defines the types result_type, arg1_type, ... (as for example boost::function does).
You can also implement it for any function object with a nontemplated operator() even if it doesn't provide arg1_type etc. typedefs, by examining the signature of its operator().
Right! Below I'm wrapping function types, pointers, and references inside a functor type boost::function; if F is instead already a functor, I leave it unchanged (see functor_wrap). Then I manipulate the type of the functor operator() to generate the function type (see functor_unwrap). That allows me to pass any function type, pointer, reference, or any functor (which defines an operator()) to make_overload (without requiring the functor to typedef result_type, arg1_type, etc) :) One question: Can I do this even without the TYPEOFs inside deduce_type below? I was not able to generate the make_overload result type without the TYPEOF (I can instead generate the overload type within the make_overload function body even without the TYPEOF using another function template to let the template system deduce the types). That is probably not a big deal because make_overload is useful when you can use it with AUTO and TYPEOF will always work in these cases. #include <boost/functional/overload.hpp> #include <boost/function.hpp> #include <boost/function_types/is_function.hpp> #include <boost/function_types/is_function_pointer.hpp> #include <boost/function_types/is_function_reference.hpp> #include <boost/function_types/function_type.hpp> #include <boost/function_types/parameter_types.hpp> #include <boost/function_types/result_type.hpp> #include <boost/type_traits/remove_pointer.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/pop_front.hpp> #include <boost/mpl/push_front.hpp> #include <boost/typeof/typeof.hpp> #include <iostream> #include <string> namespace boost { namespace functional { namespace detail { namespace overload { // Transform a function F into a functor type. // Precondition: F is a function type, a function pointer, a function // reference, or already a functor. template<typename F> class functor_wrap { template<typename MetaF> struct functor { typedef typename boost::function< typename MetaF::type > type; }; public: typedef typename boost::mpl::if_< boost::function_types::is_function<F>, functor< boost::mpl::identity<F> > , typename boost::mpl::if_< boost::function_types:: is_function_pointer< F >, functor< boost::remove_pointer< F > > , typename boost::mpl::if_< boost::function_types:: is_function_reference< F >, functor< boost::remove_reference< F > > , // Requires: It's already a functor. boost::mpl::identity< F > >::type >::type >::type ::type type; }; // Transform a functor F into a function type. template<typename F> struct functor_unwrap { typedef typename boost::function_types::function_type< typename boost::mpl::push_front< typename boost::mpl::pop_front< // Remove functor type (1st). typename boost::function_types::parameter_types<F>::type >::type , typename boost::function_types::result_type<F>::type >::type >::type type; }; template<typename F0, typename F1, typename F2> struct deduce_type { typedef boost::functional::overload< typename functor_unwrap< BOOST_TYPEOF_TPL(&(functor_wrap<F0>::type::operator())) >::type , typename functor_unwrap< BOOST_TYPEOF_TPL(&(functor_wrap<F1>::type::operator())) >::type , typename functor_unwrap< BOOST_TYPEOF_TPL(&(functor_wrap<F2>::type::operator())) >::type > type; }; } } // namespace detail::overload template<typename F0, typename F1, typename F2> typename detail::overload::deduce_type<F0, F1, F2>::type make_overload(F0 f0, F1 f1, F2 f2) { return typename detail::overload::deduce_type<F0, F1, F2>::type(f0, f1, f2); } } } // namespace boost::functional void print_s(const std::string& s) { std::cout << s << std::endl; } void print_i(int i) { std::cout << i << std::endl; } void print_d(double d) { std::cout << d << std::endl; } int main(void) { boost::function<void (double)> pd = print_d; print_s("abc"); print_i(123); pd(1.23); std::cout << std::endl; boost::functional::overload< void (const std::string&) , void (int) , void (double) > print(print_s, print_i, pd); print("abc"); print(123); print(1.23); std::cout << std::endl; BOOST_AUTO(p, boost::functional::make_overload(&print_s, &print_i, pd)); p("abc"); p(123); p(1.23); std::cout << std::endl; return 0; } Thanks! --Lorenzo