Boost logo

Boost :

From: Marco Costalba (mcostalba_at_[hidden])
Date: 2008-04-27 08:09:26


After the great success of Eric's puzzle on the common type of a given
types set here it is another puzzle for you C++ wizards.

This one arise from the multi signature boost function implementation
recently posted to this list.

Let's have two boost.function objects, each one defined on a different
function signature Sig_1, Sig_2

boost::function<Sig_1> boost_fun_1;
boost::function<Sig_2> boost_fun_2;

Then have two overloaded template functions called "set" to assign a
function/functor to either one of the above boost.function objects

 template<typename Fun>
 void set(Fun const& fun, typename enable_if<is_compatible<Fun, Sig_1>
>::type* = 0)
 {
        boost_fun_1 = fun;
 }

 template<typename Fun>
 void set(Fun const& fun, typename enable_if<is_compatible<Fun, Sig_2>
>::type* = 0)
 {
        boost_fun_2 = fun;
 }

To disambiguate between the two a SFINAE technique is used on the
second (hidden) argument of "set"

Where struct is_compatible is defined as:

   /* Check if a function/functor Fun has a given signature Sig */

    template<typename Fun, typename Sig>
    struct is_compatible
    {
        /* Check for a function */
        template<class U> static
        yes_type check(typename enable_if<is_same<U, Sig> >::type*);

        /* Check for a functor */
        template<class U, Sig U::*> struct helper;

        template<class U> static
        yes_type check(helper<U, &U::operator()>*);

        /* Default */
        template<class U> static no_type check(...);

        typedef typename boost::remove_pointer<Fun>::type F;

        static bool const value = (sizeof(check<F>(0)) == sizeof(yes_type));
    };

Now the puzzle is:

           There is a way to remove struct is_compatible altogether ?
or at least greatly simplify it ?

Constrains are

- Public API must be set(fun) where fun is any functor/function for
which either expression "boost_fun_1 = fun" or "boost_fun_2 = fun"
compiles.

- If both "boost_fun_1 = fun" and "boost_fun_2 = fun" are not
compilable then a compile error should raise

Hint: an almost working solution could have been

 template<typename Fun>
 void set(Fun const& fun, bool = (boost::function<Sig_1>() == fun))
 {
        boost_fun_1 = fun;
 }

 template<typename Fun>
 void set(Fun const& fun, bool = (boost::function<Sig_2>() == fun))
 {
        boost_fun_2 = fun;
 }

But unfortunately it is forbidden to refer to an argument (fun in this
case) in the expression of the default value of another argument.

Have fun
Marco


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