2017-01-04 6 views
2

std::bindまたはlambdaを使用して、メンバー関数へのポインタをstd::functionに変換しようとしています。 (this answer on SOからの回答後)私の試みはそうのようになります。どのようにstd :: bind(またはlambda)を推定コンテキストでstd :: functionに変換するのですか?

#include <functional> 

template<typename T> 
struct AsFunction : 
    AsFunction<decltype(&T::operator())> 
{}; 

template<class ReturnType, class... Args> 
struct AsFunction<ReturnType(Args...)> { 
    using type = std::function<ReturnType(Args...)>; 
}; 

template<class ReturnType, class... Args> 
struct AsFunction<ReturnType(*)(Args...)> { 
    using type = std::function<ReturnType(Args...)>; 
}; 

template<class Class, class ReturnType, class... Args> 
struct AsFunction<ReturnType(Class::*)(Args...) const> { 
    using type = std::function<ReturnType(Args...)>; 
}; 

template<class F> 
auto toFunction(F f) -> typename AsFunction<F>::type { 
    return {f}; 
} 

struct MyStruct { 
    int x,y; 
    void f(int){}; 
}; 

int main(){ 
    MyStruct m; 

    { 
    // this works 
    auto f = std::bind(&MyStruct::f, &m, std::placeholders::_1); 
    f(2); 
    } 

    { 
    // this doesn't 
    auto f = toFunction(std::bind(&MyStruct::f, &m, std::placeholders::_1)); 
    f(2);                                                                  
    } 

    { 
    // .. neither does this 
    auto f = toFunction([m](int x) mutable { m.f(x); }); 
    f(2); 
    } 
} 

が、私は、コンパイラから次のエラーメッセージが出ます:

// first not working 
main.cpp:24:6: note: substitution of deduced template arguments resulted in errors seen above 
main.cpp: In instantiation of ‘struct AsFunction<std::_Bind<std::_Mem_fn<void (MyStruct::*)(int)>(MyStruct*, std::_Placeholder<1>)> >’: 
main.cpp:24:6: required by substitution of ‘template<class F> typename AsFunction<F>::type toFunction(F) [with F = std::_Bind<std::_Mem_fn<void (MyStruct::*)(int)>(MyStruct*, std::_Placeholder<1>)>]’ 
main.cpp:44:75: required from here 
main.cpp:4:8: error: decltype cannot resolve address of overloaded function 
struct AsFunction : 
     ^~~~~~~~~~ 
main.cpp: In function ‘int main()’: 
main.cpp:44:75: error: no matching function for call to ‘toFunction(std::_Bind_helper<false, void (MyStruct::*)(int), MyStruct*, const std::_Placeholder<1>&>::type)’ 
    auto f = toFunction(std::bind(&MyStruct::f, &m, std::placeholders::_1)); 
                     ^
main.cpp:24:6: note: candidate: template<class F> typename AsFunction<F>::type toFunction(F) 
auto toFunction(F f) -> typename AsFunction<F>::type { 
     ^~~~~~~~~~ 
main.cpp:24:6: note: substitution of deduced template arguments resulted in errors seen above 

// second non working braces with lambda 
main.cpp: In instantiation of ‘struct AsFunction<void (main()::<lambda(int)>::*)(int)>’: 
main.cpp:4:8: required from ‘struct AsFunction<main()::<lambda(int)> >’ 
main.cpp:24:6: required by substitution of ‘template<class F> typename AsFunction<F>::type toFunction(F) [with F = main()::<lambda(int)>]’ 
main.cpp:50:55: required from here 
main.cpp:5:23: error: ‘operator()’ is not a member of ‘void (main()::<lambda(int)>::*)(int)’ 
    AsFunction<decltype(&T::operator())> 
         ^~ 
main.cpp:50:55: error: no matching function for call to ‘toFunction(main()::<lambda(int)>)’ 
    auto f = toFunction([m](int x) mutable { m.f(x); }); 
                ^
main.cpp:24:6: note: candidate: template<class F> typename AsFunction<F>::type toFunction(F) 
auto toFunction(F f) -> typename AsFunction<F>::type { 
     ^~~~~~~~~~ 
main.cpp:24:6: note: substitution of deduced template arguments resulted in errors seen above 
+0

@Holt私はOPは、結果の型と引数の型を推論したいと思います。私は正しい? –

+0

@ W.F。正確に(後でそれらを操作したい) – Patryk

+0

さて、* lambda *または 'std :: bind'を本当に使用する必要がありますか? 'toFunction(&MyStruct :: f、&m)'は大丈夫でしょうか? "lambda type"と 'std :: bind'の戻り値はインプリメンテーション定義であるため、テンプレート引数を推測するのに常に使用するのは難しいです... – Holt

答えて

2

ラムダやstd::bindの戻り値の型を引き出すのは難しいので、バインドをtoFunction内で遅らせることができます。 :

template<typename C, typename Ret, typename... Args, typename... BArgs> 
auto toFunction(Ret (C::*f)(Args...), BArgs&&... bargs) { 
    return std::function<Ret(Args...)>(std::bind(f, std::forward<BArgs>(bargs)...)); 
} 

この方法で、あなたが使用してstd::functionを取り出すことができます。

auto f = toFunction(&MyStruct::f, &m, std::placeholders::_1); 
f(2); 
0

私はあなたが少しこれをoverkillingていると思います。あなたが本当にあなたのfの明示的なstd::functionタイプをしたい場合は、あなただけのいくつかの策略で直接指定することができます。

int main(){ 
    MyStruct m; 

    { 
    std::function<decltype(std::declval<MyStruct>().f(int()))(int)> f(std::bind(&MyStruct::f, &m, std::placeholders::_1)); 
    f(2);                                                                  
    } 
} 

ははるかに最も簡単な方法は、単にタイプを指定せずにauto fを使用することです、と述べました。私はあなたがすでにそれを考えていたと仮定していて、それはあなたのケースではできませんが、とにかくこれを言います。

+0

私はあなたが引数の種類を知る必要があると思うこの方法だと思う... –

+1

ああ私が参照してください。上記のように、あなたは引数型を与えるためにテンプレート型を使って 'toFunction'呼び出しに簡単に移動できます。デモのために答えを修正しましょう – Smeeheey

関連する問題