c_function と lambda expressions を組み合わせる


さて、c_function lambda expressions の組み合わせについては上記のサイトを参照してもらえれば分かると思います。
c_function を使用する場合、ユニークな型を使用する必要がありますが、それを lambda expressions を使用しようという話ですね。
確かに lambda expressions decltype([]{}) のように decltype で使用することは出来ませんが、上記の場合だと引数として渡せば解決出来そうなのでやってみました。

[ソース]

template<typename Unique, typename FuncType, typename Func>
struct c_function_impl;

template<typename Unique, typename Result, typename ...Args, typename Func>
struct c_function_impl<Unique, Result(*)(Args...), Func>{
    static Result
    call(Args... args){
        return func(args...);
    }
    static Func func;
};


template<typename Unique, typename Result, typename ...Args, typename Func>
Func c_function_impl<Unique, Result(*)(Args...), Func>::func;


template<typename Unique, typename FuncType, typename Func>
FuncType
make_c_function(Func func){
    c_function_impl<Unique, FuncType, Func>::func = func;
    return &c_function_impl<Unique, FuncType, Func>::call;
}

template<typename FuncType, typename Lambda, typename Func>
FuncType
make_c_function(Lambda, Func func){
    return make_c_function<Lambda, FuncType>(func);
}


#include <iostream>

using func_type = int(*)();

void
printer(func_type func){
    std::cout << func() << std::endl;
}

struct value{
    int operator ()() const{
        return value_;
    }
    int value_;
};

template<typename T>
constexpr int
func(T){
    return 0;
}


int
main(){
    {
        auto f1 = make_c_function<struct Unique1, int(*)()>(value{1});
        auto f2 = make_c_function<struct Unique2, int(*)()>(value{2});
        // 間違えて同じ型名を使ってしまった
        auto f3 = make_c_function<struct Unique2, int(*)()>(value{3});
        printer(f1);  // 1
        printer(f2);  // 3
        printer(f3);  // 3
    }

    {
        // []{} を渡すだけなので名前を考える必要がない
        auto f1 = make_c_function<int(*)()>([]{}, value{1});
        auto f2 = make_c_function<int(*)()>([]{}, value{2});
        auto f3 = make_c_function<int(*)()>([]{}, value{3});
        printer(f1);  // 1
        printer(f2);  // 2
        printer(f3);  // 3
    }

    return 0;
}

[出力]

1
3
3
1
2
3

問題なく動いているみたいですね。
これで C言語API を使用している時に『関数オブジェクトを関数ポインタに渡したくてしょうが無い』って事が解決できるかな。
std::bind とかも使用できますしね。

[コンパイラ]

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