
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