#include <functional> #include <iostream> // handle mixed type operations by selecting a "winning" type to promote to // By default this should be symmetric. template <class T, class U> struct promote : public promote<U,T> { }; template <class T> struct promote<T,T> { typedef T result_type; }; template <> struct promote<double,int>{ typedef double result_type; }; // get result type from a templated binary functor with one template parameter. template <template <class> class F, class T, class U > struct get_result_type { typedef typename promote<T,U>::result_type result_type; }; // given a binary functor F with one template parameter, what template parameter // should we instantiate it with if we want to call it on types T and U ? template <template <class> class F, class T, class U > struct get_template_parameter { typedef typename promote<T,U>::result_type result_type; }; template <template <class> class Base, class T > struct X : public Base<T> {}; template <template <class> class Base> struct X<Base,void> { template <class T> T operator() (const T& arg) { return Base<T>()(arg); } template <class T> T operator() (const T& left, const T& right) { return Base<T>()(left,right); } template <class T, class U> typename get_result_type<Base,T,U>::result_type operator() (const T& left, const U& right) { return Base<get_template_parameter<Base,T,U>::result_type>() (left,right); } }; int main(int argc, char** argv) { X<multiplies,double> x; X<multiplies,void> y; X<plus,int> z; X<plus,void> t; std::cout << x(2,3.4) << std::endl; std::cout << y(2.,3.4) << std::endl; std::cout << y(2,3) << std::endl; std::cout << z(2,3) << std::endl; std::cout << t(2,3) << std::endl; std::cout << t(2.1,3.) << std::endl; // works because of promotes template std::cout << t(2.1,3) << std::endl; std::cout << t(2,3.4) << std::endl; }