2005年9月 8日

C++ の関数ポインタ

関数をオーバーロードしたり、テンプレート化した場合に関数ポインタが使えるかどうか気になったので試してみました。

 
#include <iostream>
using namespace std;

void func(int x) {
    cout << "func(int)" << endl;
}

void func(double x) {
    cout << "func(double)" << endl;
}

template<typename T>
void func(T x) {
    cout << "func(T)" << endl;
}

template<typename T>
void funcfunc(void (*f)(T x)) {
    f(0);
}

int main () {
    void (*f1)(int) = func;
    void (*f2)(double) = func;
    void (*f3)(char) = func;
    f1(0);  // func(int)
    f2(0);  // func(double)
    f3(0);  // func(T)

    // funcfunc(func);  // これはダメ
    funcfunc(static_cast<void (*)(int)>(func));  // func(int)
}

上のコードを実行すると期待通り、func(int), func(double), func(T), func(int) と一行づつ表示されます。

最初の 3 つの func 関数は異なる引数でオーバーロードされた関数です。これらの関数へのポインタを使うときは、関数ポインタ用の変数の型を適切に宣言して代入すれば OK です。func(char x) は存在しないので f3 は func(T x) へのポインタになります。これらの例では曖昧性は発生しません。

一方、 funcfunc は、「引数がテンプレート化された関数へのポインタ」を引数として受け取る関数です。この関数の呼び出しは funcfunc(func) では曖昧性があるので、どの関数のポインタを渡すかをキャストを使って明示しています。func が 1つしないとき (オーバーロードされていないとき) は funcfunc(func) で OK です。

というわけで、特に問題なく使えるという結果でした。C++ は関数オブジェクト、バーチャル関数、テンプレートなどがあるので関数ポインタを使う機会はあまり多くはないと思いますが。