引数の型だけ違う(関数オブジェクト|関数)の処理をtemplateで切り分ける
の続編。関数オブジェクトだけじゃなくて、関数でもOKにしてみた。ラムダ式でも動いた。関数ポインタが混ざってくると混乱する。
#include<iostream> #include<vector> #include<type_traits> //適当なfunction traits template<typename T_> struct function_traits{}; template<typename C_, typename R_, typename Arg_> struct function_traits<R_(C_::*)(Arg_) const>{ typedef Arg_ argument; }; template<typename R_, typename Arg_> struct function_traits<R_(Arg_)>{ typedef Arg_ argument; }; //Tag(Vector or Double) struct tagV{}; struct tagD{}; //Tag(Class(Functor) or Function) struct tagC{}; struct tagF{}; template<typename T_> struct call_traits { typedef tagC object_type; typedef typename std::conditional<std::is_same<typename function_traits<decltype(&T_::operator())>::argument, double>::value, tagD, tagV>::type argument_type; }; template<class R_, class Arg_> struct call_traits<R_(Arg_)> { typedef tagF object_type; typedef typename std::conditional<std::is_same<Arg_, double>::value, tagD, tagV>::type argument_type; }; //タグに応じた実際の処理 template<typename T_> void call_detail(const T_ & t, std::vector<double> x, tagV){ t(x); } template<typename T_> void call_detail(const T_ & t, std::vector<double> x, tagD){ t(x[0]); } template<class T_> void call(const T_ & t, std::vector<double> x) { call_detail(t, x, call_traits<T_>::argument_type()); } //引数の型が違うクラス&関数 void a(double){ std::cout << "I'm function A" << std::endl; } void b(double){ std::cout << "I'm function B" << std::endl; } struct A{ void operator()(double x) const{ std::cout << "I'm class A:" << x << std::endl; } }; struct B{ void operator()(std::vector<double> x)const{ std::cout << "I'm class B:" << x[0] << ", " << x[1] << ", " << x[2] << std::endl; } }; //メイン int main() { std::vector<double> xxx = { 1, 2, 3 }; call(A(), xxx); call(B(), xxx); call(a, xxx); call(b, xxx); call([](double x){std::cout << "I'm lambda." << std::endl; }, xxx); return 0; }
実行結果
I'm class A:1 I'm class B:1, 2, 3 I'm function A I'm function B I'm lambda.