2014-01-19 5 views
12

부분적으로 나머지 인수를 명시 적으로 지정하지 않고도 호출 가능 객체 (예 : 함수)의 인수를 첫 번째/마지막 n에 바인드 할 수 있습니까? 함수 인수의 부분 바인딩

std::bind()

모든 인수 바인딩 할 것을 요구하는 것 등

_3이 가능한 부분에 대한 bind_first()/bind_last()를 작성하는 것입니다, _2, std::placeholders::_1에 바인딩해야합니다 왼쪽되어야하는 것들 첫 번째/마지막 인수에서 바인딩을 시작하고 바인딩되지 않은 나머지 인수에 대한 자리 표시자를 원래 위치의 원래 순서대로 자동 삽입합니다.

+0

거기에'표준 : bind1st'는하지만 추천하지 않습니다. – Gasim

+0

구현할 수 없다는 두려움이 있습니다. – Paranaix

+0

이것은 실제로 작성하기가 쉽지 않습니다. 바운드 인수를'튜플 (tuple) '에 저장하고, 가변 수의 매개 변수를'operator()'에 받아들이고, 인덱스를 통해 튜플을 압축 해제 한 다음 실제 인수를 추가하면됩니다. – Xeo

답변

0

질문에 영감을 받아 필자는 자신 만의 프리 바인딩을 처음부터 작성했습니다. 그것은 다른 모든 사람들과 꽤 비슷하게 보였지만, 원래는 약속합니다 :) - 수렴 진화라고 부릅니다.

그러나 약간 다른 풍미가 있습니다. 한 가지 방법은 생성자에게 전달하지만, std::decay을 사용하는 것을 선호 할 수 있습니다 (어떤면에서는 더 의미가 있지만 어디서나 std::ref을 쓰는 것을 좋아하지 않습니다). 다른 하나는 중첩 된 prebinds에 대한 지원을 추가 했으므로 prebind(foo, prebind(GetRandomNumber))()prebind(foo)(GetRandomNumber())과 같습니다.

#include <tuple> 
#include <type_traits> 
using namespace std; 

struct pb_tag {}; //use inheritance to mark prebinder structs 

//result_of_t will be defined by default in c++1y 
template<typename T > using result_of_t = typename result_of<T>::type; 
template<typename T> using is_prebinder = is_base_of<pb_tag, typename remove_reference<T>::type >; 

//ugly sequence generators for something different 
template<int N, int ...S> struct seq : seq<N-1, N, S...> {}; 
template<int ...S> struct seq<0, S...> {typedef seq type;}; 

//these three functions are only for nested prebind. they map 
//T t -> T t and Prebind<f, T...> -> f(T...) 
template<typename T> 
auto dispatchee(T&& t, false_type) -> decltype(forward<T>(t)){ 
    return forward<T>(t); 
} 

template<typename T> 
auto dispatchee(T&& t, true_type) -> decltype(t()) 
{ 
    return t(); 
} 

template<typename T> 
auto expand(T&& t) -> decltype(dispatchee(forward<T>(t), is_prebinder<T>())) 
{ 
    return dispatchee(forward<T>(t), is_prebinder<T>()); 
} 

template<typename T> using expand_type = decltype(expand(declval<T>())); 

//the functor which holds the closure in a tuple 
template<typename f, typename ...ltypes> 
struct prebinder : public pb_tag 
{ 
    tuple<f, ltypes...> closure; 
    typedef typename seq<sizeof...(ltypes)>::type sequence; 
    prebinder(f F, ltypes... largs) : closure(F, largs...) {} 

    template<int ...S, typename ...rtypes> 
    result_of_t<f(expand_type<ltypes>..., rtypes...)> 
    apply(seq<0, S...>, rtypes&& ... rargs){ 
     return (get<0>(closure))(expand(get<S>(closure))... , forward<rtypes>(rargs)...); 
    } 

    template<typename ...rtypes> 
    result_of_t<f(expand_type<ltypes>..., rtypes...)> 
    operator() (rtypes&& ... rargs){ 
     return apply(sequence(), forward<rtypes>(rargs)...); 
    } 
}; 

template<typename f, typename ...ltypes> 
prebinder<f, ltypes...> prebind(f&& F, ltypes&&... largs) 
{ 
    return prebinder<f, ltypes...>(forward<f>(F), forward<ltypes>(largs)...); 
} 

쉽게 이전 바인딩으로 변경할 수 있습니다.

사용 보인다 같은 :

int g(int a){ return 1 + a; } 

int h(){ return 1; } 

int i(int a, int b, int c, int d){ 
    return 1 + a + b + c + d; 
} 

int main() 
{ 
    //completely bound 
    auto a = prebind(g, 1); 
    cout << a() << endl; 

    //nested bind by reference 
    auto b = prebind(g, a); 
    cout << b() << endl; 
    get<1>(a.closure) = 2; 
    cout << b() << endl; 

    //bind to prebinder 
    auto c = prebind(b); 
    cout << c() << endl; 

    //nested bind of temp to temp 
    auto d = prebind(prebind(g), prebind(h)); 
    cout << d() << endl; 

    //and the one you wanted orginally 
    auto e = prebind(i, 1, 1, 1); 
    cout << e(1) << endl; 

    return 0; 
} 
+0

확실합니까? 나는 무수한 경우에 똑같은 생각을했고 항상 그것이 사실이 아니라는 것을 발견했다. –

+0

[라이브 예제.] – user3125280

6

어느 부스트도 자동으로 공백의 표준 라이브러리 bind 채우기. 비오는 저녁을 채우려면 혼자서 그런 가제트를 쓸 수 있습니다. 여기에만 일반 함수의 인수를 후행에 대한 예는 다음과 같습니다

#include <tuple> 
#include <type_traits> 
#include <utility> 

template <typename F, typename ...Args> struct trailing_binder; 

template <typename R, typename ...Frgs, typename ...Args> 
struct trailing_binder<R(Frgs...), Args...> 
{ 
    template <typename ...Brgs> 
    trailing_binder(R (*f)(Frgs...), Brgs &&... brgs) 
    : the_function(f) 
    , the_args(std::forward<Brgs>(brgs)...) 
    { } 

    template <unsigned int ...I> struct intlist {}; 

    template <typename ...Brgs> 
    typename std::enable_if<sizeof...(Brgs) + sizeof...(Args) == sizeof...(Frgs), R>::type 
    operator()(Brgs &&... brgs) 
    { 
     return unwrap(std::integral_constant<bool, 0 == sizeof...(Args)>(), 
         intlist<>(), 
         std::forward<Brgs>(brgs)...); 
    } 

private: 
    template <unsigned int ...I, typename ...Brgs> 
    R unwrap(std::false_type, intlist<I...>, Brgs &&... brgs) 
    { 
     return unwrap(std::integral_constant<bool, sizeof...(I) + 1 == sizeof...(Args)>(), 
         intlist<I..., sizeof...(I)>(), 
         std::forward<Brgs>(brgs)...); 
    } 

    template <unsigned int ...I, typename ...Brgs> 
    R unwrap(std::true_type, intlist<I...>, Brgs &&... brgs) 
    { 
     return the_function(std::get<I>(the_args)..., std::forward<Brgs>(brgs)...); 
    } 

    R (*the_function)(Frgs...); 
    std::tuple<Args...> the_args; 
}; 

template <typename R, typename ...Args, typename ...Frgs> 
trailing_binder<R(Frgs...), Args...> trailing_bind(R (*f)(Frgs...), Args &&... args) 
{ 
    return trailing_binder<R(Frgs...), typename std::decay<Args>::type...>(f, std::forward<Args>(args)...); 
} 

사용법 :

int f(int a, int b, int c, int d) { return a + b + c + d; } 

int main() 
{ 
    auto b = trailing_bind(f, 1); 
    return b(3, 8, 13); 
} 
+0

나는이 질문에 대한 나의 코멘트 - 링크를 체크 아웃하는 것이 좋습니다. :) – Xeo

+0

@ Xeo : 모든 컴파일러 오류가있는 링크를 의미합니까? :-) 목표는'bind (f, 1)'와 같은 것으로 3 개의 매개 변수로 호출 가능을 반환한다는 점에 유의하십시오. –

+0

* 질문 *에 다른 대답이 아닙니다. : P – Xeo