$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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