Boost logo

Boost :

Subject: Re: [boost] [functional] adding overload
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-01-17 05:25:59


On Mon, Jan 16, 2012 at 5:34 PM, Nathan Ridge <zeratul976_at_[hidden]> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk