関数テンプレートのポインタを関数で受け取る

関数テンプレートのポインタを関数に渡す場合、

template<typename T, typename Func>
T
calc(T a, T b, Func func){
    return func(a, b);
}

template<typename T>
T
plus(T a, T b){
    return a + b;
}

assert(calc(1, 2, &plus<int>) == 3, "");   // ok
assert(calc(1, 2, &plus) == 3, "");        // error

こんな感じで呼び出し側で明示的に型を定義しないと渡せないと思っていたんですが、受け取り側で関数ポインタ型を定義しておけば問題なく渡せるんですね。

[ソース]

#include <boost/mpl/identity.hpp>

template<typename T>
T
calc(T a, T b, typename boost::mpl::identity<T(*)(T, T)>::type func){
    return func(a, b);
}

template<typename T>
T
plus(T a, T b){
    return a + b;
}

#include <cassert>

int
main(){

    assert(calc(1, 3, &plus) == 4);

    return 0;
}

これは知らなかったなー。
ただし、上記のままでは関数オブジェクトを渡すことは出来ません。
C++11 の場合だとこんな感じになるのかな。

// テンプレートのデフォルト値に関数ポインタ型を定義
template<typename T, typename Func = T(*)(T, T)>
constexpr T
calc(T a, T b, Func func){
    return func(a, b);
}

template<typename T>
constexpr T
plus(T a, T b){
    return a + b;
}

struct minus{
    template<typename T>
    constexpr T
    operator ()(T a, T b) const{
        return a - b;
    }
};

int
main(){
    static_assert(plus(1, 2) == 3, "");
    static_assert(calc(1, 2, &plus<int>) == 3, "");
    static_assert(calc(1, 2, &plus) == 3, "");
    static_assert(calc(1, 2, minus{}) == -1, "");   // ok
    return 0;
}

まぁこの場合でもテンプレート関数の引数型が参照であったりするとエラーになったりするんですが。

[コンパイラ]

  • g++ (GCC) 4.7.0 20120218 (experimental)
  • clang++ (LLVM) 3.1 20120226(trunk)