2017-01-04 6 views
2

포인터를 std::bind 또는 lambdas를 사용하여 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 나는 영업 이익은 결과 유형과 인수의 유형을 추론하고자 생각합니다. 내가 맞습니까? –

+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