関数ポインタ、あるいはそれをテンプレートの特殊化で捌く時用のメモ

鳥頭化がひどいのでメモっておこうって。
結論として

  • function_traitsの特殊化で、「R_(Arg_)」と「R_(*)(Arg_)」は区別され、それはdecltype(hoge)なのかdecltype(&hoge)なのかに依る
  • typeid関数に対しても&を付けてhoge関数を渡すか渡さないかで、void (__cdecl*)(int)となるかvoid (__cdecl)(int)となるかが別れる(上の話と整合的)
  • 関数ポインタに関数を渡す時は6つけてもつけなくてもいいし、その関数ポインタから関数を実行する時も、*を付けてもつけなくてもいい

ってところかな。

#include<iostream>
//オレオレfunction traits
template<typename T_> 
struct function_traits;
template<typename R_, typename Arg_>
struct function_traits<R_(Arg_)>
{
	typedef Arg_ argument;
	static const int X = 1;
};
template<typename R_, typename Arg_>
struct function_traits<R_(*)(Arg_)>
{
	typedef Arg_ argument;
	static const int X = 333;
};
//適当な関数
void hoge(int x){ std::cout << "I'm hoge" << std::endl; }
//Main
int main()
{
	std::cout << "hogeに対するtypeidの適用結果" << std::endl;
	std::cout << "hogeのtypeid" << std::endl;
	std::cout << typeid(hoge).name() << std::endl;
	std::cout << "&hogeのtypeid" << std::endl;
	std::cout << typeid(&hoge).name() << std::endl;
	std::cout << "*hogeのtypeid" << std::endl;
	std::cout << typeid(*hoge).name() << std::endl;

	std::cout << std::endl;
	std::cout << "function_traitsのR_(Arg_)=1に特殊化されるか、それともR_(*)(Arg_)=333となるか" << std::endl;
	std::cout << "hogeの場合" << std::endl;
	std::cout << function_traits<decltype(hoge)>::X << std::endl;
	std::cout << "&hogeの場合" << std::endl;
	std::cout << function_traits<decltype(&hoge)>::X << std::endl;
	std::cout << "*hogeの場合" << std::endl;
	std::cout << function_traits<decltype(*hoge)>::X << std::endl;

	std::cout << std::endl;
	std::cout << "関数ポインタの復習的なもん" << std::endl;
	//適当にtypdef
	typedef void(*Func)(int);
	//typedef void(Gunc)(int); は当然だめ
	//&つけてもつけなくてもOKぽい
	Func f = hoge; 
	Func g = &hoge;
	//*つけてもつけなくてもOKぽい
	f(1);
	(*g)(1);
	return 0;
}

実行結果

hogeに対するtypeidの適用結果
hogeのtypeid
void __cdecl(int)
&hogeのtypeid
void (__cdecl*)(int)
*hogeのtypeid
void __cdecl(int)

function_traitsのR_(Arg_)=1に特殊化されるか、それともR_(*)(Arg_)=333となるか
hogeの場合
1
&hogeの場合
333
*hogeの場合
1

関数ポインタの復習的なもん
I'm hoge
I'm hoge