関数ポインタ。
いつもtypedefしているから関数ポインタを返す関数を書くことで悩むことが無かった。
否、悩みたくないから関数ポインタをtypedefしていたという方が正しいでしょう。
ではtypedefを使わずに関数ポインタを返す関数を書く、且つその関数へのポインタの型を書くことは出来るのか(言語としてではなく自分の知識としてです)
以下のようなプログラムを書いて段階的に難しくなるようにしてみました。基本的にCでもC++でも変わりませんが、C++ではtypeidがあるので型名を取得できます。
折角なのでその機能を利用し、C++環境ではよりわかりやすい出力結果が出るように してみました。
※このプログラムはCでもC++でもどちらでもコンパイルできるようにしてあります。ここに載せている実行結果はVC2008のものです。
#ifdef __cplusplus
#include <cstdio>
#include <typeinfo>
using namespace std;
#else
#include <stdio.h>
#endif
#ifdef __cplusplus
#define SHOW_TYPE(func, var) func; printf("%-30s %s\n", #func, typeid(var).name())
#else
#define SHOW_TYPE(func, var) func;
#endif
/* 関数ポインタで呼び出される関数本体 */
void foo(int i) { printf("foo(%d);\n", i); }
void bar(void (*f)(int), int i) { printf("bar(%p, %d); ", f, i); f(i); }
void (*foo_getter(void))(int) { printf("foo_getter(); "); return foo; }
void (*foo_returner(void (*f)(int)))(int) { printf("foo_returner(%p);", f); return f; }
/* 関数ポインタ */
void (*foo_v)(int) = foo;
void (*foo_vs[1])(int) = { foo };
/* 関数ポインタを引数としてとる関数へのポインタ */
void (*bar_v)(void (*)(int), int) = bar;
void (*bar_vs[1])(void (*)(int), int) = { bar };
/* 関数ポインタを戻り値とする関数へのポインタ */
void (*(*foo_getter_v)(void))(int) = foo_getter;
void (*(*foo_getter_vs[1])(void))(int) = { foo_getter };
/* 関数ポインタを引数として取り関数ポインタを戻り値とする関数へのポインタ */
void (*(*foo_returner_v)(void (*)(int)))(int) = foo_returner;
void (*(*foo_returner_vs[1])(void (*)(int)))(int) = { foo_returner };
int main()
{
SHOW_TYPE(foo_v(1), foo_v);
SHOW_TYPE(foo_vs[0](2), foo_vs);
SHOW_TYPE(bar_v(foo, 3), bar_v);
SHOW_TYPE(bar_vs[0](foo, 4), bar_vs);
SHOW_TYPE(foo_getter_v()(5), foo_getter_v());
SHOW_TYPE(foo_getter_vs[0]()(6), foo_getter_vs[0]());
SHOW_TYPE(foo_returner_v(foo)(7), foo_returner_v(foo));
SHOW_TYPE(foo_returner_vs[0](foo)(8), foo_returner_vs[0](foo));
return 0;
}
Cでの実行結果
foo(1);
foo(2);
bar(00401000, 3); foo(3);
bar(00401000, 4); foo(4);
foo_getter(); foo(5);
foo_getter(); foo(6);
foo_returner(00401000);foo(7);
foo_returner(00401000);foo(8);
C++での実行結果
foo(1);
foo_v(1) void (__cdecl*)(int)
foo(2);
foo_vs[0](2) void (__cdecl*[1])(int)
bar(00401000, 3); foo(3);
bar_v(foo, 3) void (__cdecl*)(void (__cdecl*)(int),int)
bar(00401000, 4); foo(4);
bar_vs[0](foo, 4) void (__cdecl*[1])(void (__cdecl*)(int),int)
foo_getter(); foo(5);
foo_getter_v()(5) void (__cdecl*)(int)
foo_getter(); foo(6);
foo_getter_vs[0]()(6) void (__cdecl*)(int)
foo_returner(00401000);foo(7);
foo_returner_v(foo)(7) void (__cdecl*)(int)
foo_returner(00401000);foo(8);
foo_returner_vs[0](foo)(8) void (__cdecl*)(int)
尚、gcc/g++でのプログラムと実行結果は以下のリンク先にあります
(g++でマングリングされた型をわかりやすくするためソースに手が入れてあるので)
gcc
http://ideone.com/lpOfq
g++
http://ideone.com/AC4il