2011-08-01 3 views
0

std :: bind 함수 랩퍼가 필요합니다. std :: bind는 래퍼 함수 앞에 호출되어 랩핑 된 함수에 인수를 전달합니다.C++에서 std :: bind 용 함수 데코레이터 0x

std::function<void (int)> foo = postbind<int>(service, handle); 

지금까지 내가 그 템플릿 매개 변수를 제거 할 수있는 방법이

std::function<void (int)> foo = postbind(service, handle); 

까지있어? 그것은 지능이 충분하지 않은 객체 생성 함수 (postbind)에서 형식 공제로 내려 오는 것 같습니다.

#include <functional> 

template<typename T> 
void foo(std::function<void (T)> func) 
{ 
} 

void handler(int x) 
{ 
} 

int main() 
{ 
    foo(handler); 
    return 0; 
} 

오류를 말한다 : 아직까지 전화 'foo는 (무효 (&) (INT))'

에 대한 매칭 기능, 코드 샘플 :

template<typename T> 
void foo(T t) 
{ 
} 

int main() 
{ 
    foo(99); 
    return 0; 
} 

이 작동하지 않습니다. 어떤 아이디어가이 작품을 만드는 방법? std :: bind를 전달할 수 있어야하고 결과가 std :: function으로 성공적으로 캐스팅 될 수 있어야합니다.

어떻게 템플릿 매개 변수를 제거 할 수 있습니까? 감사.


Q. 서비스 란 무엇이며이 클래스는 무엇을 의미합니까?

가. 현재 스레드에서 boost :: asio :: io_service-> posts의 함수 래퍼를 캡슐화합니다.


전체 소스 코드 :

template <typename R, typename A> 
struct wrap 
{ 
    typedef std::function<R(A)> func; 

    wrap(func f_) : f(f_) { } 

    void prebind(func g) { prebound.push_back(g); } 

    R operator()(A arg) 
    { 
    for (auto it = prebound.cbegin(); it != prebound.cend(); ++it) 
    { 
     func g = *it; 
     g(arg); 
    } 

    f(arg); 
    } 
private: 
    std::vector<func> prebound; 
    func f; 
}; 

wrap<void, int> make_wrap(std::function<void(int)> f) 
{ 
    return wrap<void, int>(f); 
} 

:

#include <iostream> 
#include <functional> 
#include <memory> 

class io_service 
{ 
}; 

typedef std::shared_ptr<io_service> service_ptr; 

template <typename Arg1> 
class postbind_impl_1 
{ 
public: 
    typedef std::function<void (Arg1)> function; 

    postbind_impl_1(service_ptr service, function memfunc) 
     : service_(service), memfunc_(memfunc) 
    { 
    } 

    void operator()(Arg1 arg1) 
    { 
     // do stuff using io_service 
     memfunc_(arg1); 
    } 
private: 
    service_ptr service_; 
    function memfunc_; 
}; 

template <typename Arg1> 
postbind_impl_1<Arg1> postbind(service_ptr service, 
     typename postbind_impl_1<Arg1>::function handle) 
{ 
    return postbind_impl_1<Arg1>(service, handle); 
} 

// ---------------- 

void handle(int x) 
{ 
    std::cout << x << "\n"; 
} 

int main() 
{ 
    service_ptr service; 
    std::function<void (int)> foo = postbind(service, handle); 
    foo(110); 
    return 0; 
} 
+0

'service'와'handle' 무엇입니까? 의도 한 용도의 예를 들려 줄 수 있습니까? –

+0

님이 위에 질문에 답변했습니다. ATM std :: bind를 사용하여 함수를 전달합니다.이 함수는 처리가 완료된 후 핸들 (...)을 호출하는 작업 (예 : handle_connect)에 전달합니다. handle_connect가 별도의 스레드에서 실행되는 API의 일부인 경우 내부적으로 thread_ugly를 전환하기 위해 handle_connect를 do_handle_connect에 게시해야합니다. 차라리 io_service를 전달하는 자동 래퍼가 필요합니다. – genjix

답변

0

/* 
* Defines a function decorator ala Python 
* 
* void foo(int x, int y); 
* function<void()> wrapper(function<void (int)> f); 
* 
* auto f = decorator(wrapper, bind(foo, 110, _1)); 
* f(); 
*/ 

#include <functional> 

template <typename Wrapper, typename Functor> 
struct decorator_dispatch 
{ 
    Wrapper wrapper; 
    Functor functor; 

    template <typename... Args> 
    auto operator()(Args&&... args) 
     -> decltype(wrapper(functor)(std::forward<Args>(args)...)) 
    { 
     return wrapper(functor)(std::forward<Args>(args)...); 
    } 
}; 

template <typename Wrapper, typename Functor> 
decorator_dispatch< 
    Wrapper, 
    typename std::decay<Functor>::type 
> 
decorator(Wrapper&& wrapper, Functor&& functor) 
{ 
    return {wrapper, functor}; 
} 
0

내가 여기 당신이 달성하려고하는지 전혀 모르겠어요,하지만 행동의 목록을 저장하는 순진한 래퍼 용도 :

auto foowrap = make_wrap(foo); 

foowrap.prebind(std::function<void(int)>(action1); 
foowrap.prebind(std::function<void(int)>(action2); 

foowrap(12); // calls action1(12), action2(12), foo(12) 
+0

이제 make_wrap 함수를 템플릿으로 만들어보십시오. 따라서 템플릿 인수를 제공 할 필요가 없으므로 foo에서 자동으로 유형을 추론 할 수 있습니다. – genjix

+0

흠, 잠깐, 내가 방금 잘못 생각한 것 같아 - 당신은 이미'make_wrap'에서 템플릿 매개 변수를 생략 할 수 있어야합니다. 내가 편집하게 해줘. –

+0

이 문제이다 템플릿 표준 : 함수 make_wrap (표준 : 함수 F) { 창 랩 (F); } 해당 템플릿이 함수를 매개 변수화했습니다. 이제 템플릿 인자없이 호출하십시오 : auto foowrap = make_wrap (foo); – genjix

2

어떻게해야합니까? 컴파일러가 std::function을 사용하는 것을 알기를 기대하십니까? 이 코드에서 :

#include <functional> 

template<typename T> 
void foo(T func) 
{ 
} 

void handler(int x) 
{ 
} 

int main() 
{ 
    foo(handler); 
    return 0; 
} 

Tstd::function<void (int)>은 아닙니다. 그것은 void (&)(int)입니다 (오류 메시지가 말한 것처럼), 함수에 대한 참조가 아니라 펑터 객체입니다.

작동합니다 전달 함수의 인수 형식의 공제, 시도 :

#include <functional> 

template<typename T> 
std::function<void (T)> foo(void (*func)(T)) 
{ 
} 

void handler(int x) 
{ 
} 

int main() 
{ 
    foo(handler); 
    return 0; 
} 

데모 :

당신이 std::function 또는 일반 함수 포인터 중 하나에서 인수 유형을 추출해야하는 경우 http://ideone.com/NJCMS, 당신 '

template<typename> 
struct getarg {}; 

template<typename TArg> 
struct getarg<std::function<void (TArg)>> { typedef TArg type; }; 

template<typename TArg> 
struct getarg<void (*)(TArg)> { typedef TArg type; }; 

template<typename TArg> 
struct getarg<void (&)(TArg)> { typedef TArg type; }; 

template<typename T> 
std::function<void (typename getarg<T>::type)> foo(T func) 
{ 
} 

void handler(int x) 
{ 
} 

int main() 
{ 
    foo(handler); 
    return 0; 
} 

데모 : http://ideone.com/jIzl7

도우미 구조를해야 할 것이다 C++ 0x로

은 또한 반환 std::bind의 값과 람다를 포함하여 암시 적으로 std::function로 변환 아무것도 일치시킬 수 있습니다 : 바인드 표현의 http://ideone.com/6pbCC

+0

그 문제는 std :: bind에서 작동하지 않는다는 것입니다. 즉 std :: function foo = postbind (service, std :: bind (handle, _1, 9)); – genjix

+0

@user : 부분 전문화 및 typedef를 사용하여 어떻게 수행 할 수 있는지 보여주었습니다. 업데이트를 참조하십시오. –

+0

놀라운! 이러한 프록시 객체를 사용하면 효과적입니다. 어떻게 std :: bind를 std :: function으로 자동 변환하도록 할 수 있습니까? std :: function b = postbind (service, std :: function (std :: bind (handle, _1, 9))); – genjix

3

AFAICT 인수 유형 추론 될 수 없습니다, 그래서 당신이 원하는 예쁜입니다 많이 불가능합니다. 이 :) 불가능했다 모든 반대자으로