2011-11-09 16 views
10

Chcę wiedzieć, czy możliwe jest użycie liczby argumentów przekazanych do szablonu variadic jako symbol zastępczy w wywołaniu boost :: bind.Zwiększ wartość argumentu zastępczego wiązania równą liczbie argumentów Variadic Template

coś takiego:

template <typename ... Args> 

boost::bind(&function, this, anArg, _1));   //If Args count equals 1 
boost::bind(&function, this, anArg, _1, _2));  //If Args count equals 2 
boost::bind(&function, this, anArg, _1, _2, _3)); //If Args count equals 3 

Czy to możliwe?

Dziękuję

+4

Istnieje dobra implementacja narzędzia make_indice tutaj: [http://preney.ca] (http://preney.ca/paul/2011/10/16/applying-stdtuple-to-functors-efficiently/) ale trudno mi się zastanowić, w jaki sposób mogę go użyć z boost :: arg <> – Blizter

+0

Ten link był świetny do odczytu, a funkcja 'apply (Func, std :: tuple)' może być przydatna pewnego dnia . –

+0

Widzę "nazwa_typu ... Args". Czy używasz C++ 11? – kennytm

Odpowiedz

1

Tam na pewno jest to sposób z częściowym specjalizacji. Twój variadic nie zna liczby argumentów od razu, prawda? musisz używać rekurencji w czasie kompilacji, w tym czasie możesz układać argumenty za pomocą metody boost :: mpl (lub liczyć je za pomocą prostego stałego stałego przyrostu). następnie w twoim ostatnim nie-variadycznym wywołaniu rekurencyjnym (z 0 arg) wywołujesz mpl :: size na twoim kontenerze (lub po prostu używasz integralnego licznika, jeśli wybrałeś w ten sposób), aby wywołać Call'a, tak jak druga odpowiedź, która nosi wszystkie argumenty plus jeden zintegrowany parametr szablonu na początku listy typów. i to jest to, co specjalizujesz. tworzysz wywołującego dla każdej liczby argumentów, które wywołają poprawne powiązanie zgodnie z jego wyspecjalizowaną liczbą argumentów. (Struktury, które można wywoływać, są (częściowo) wyspecjalizowane zgodnie z liczbą argumentu, parametr całkowego szablonu i nawet jeśli funkcja Call przyjmuje maksymalną liczbę argumentów, zawija tylko prawidłowe wywołanie typu boost :: bind, na przykład bind (.. , _1, _2) dla Callable < 2, T1, T2, T3>) to nie jest straszne, ale potwierdzam, że użyłem tego podejścia w C++ 03 w przeszłości.

0

Może Pan wyjaśnić, co chcesz robić w nieco bardziej szczegółowo. Jeśli dopiero szukasz rozwiązania do obsługi trzech różnych podpisów, które różnią się od ich typów parametrów, można zrobić coś takiego:

template<typename signature> 
struct callable; 

template<typename P0, typename P1, typename P2> 
struct callable<void (P0, P1, P2)> 
{ 
    void bind() 
    { 
     boost::bind(&callable::operator(), this, _1, _2, _3); 
    } 

    void operator()(P0, P1, P2) {} 
}; 
0

To nie jest odpowiedź na konkretny problem, ale dobre obejście problemu, który prawdopodobnie próbujesz rozwiązać.

Wystąpił ten sam problem przy wdrażaniu ogólnego mechanizmu przekazywania. Moim rozwiązaniem było użycie wrappera na samym wywołaniu bindowania, specjalizującym się w odmianach. Chociaż nie rozwiązuje problemu, zdecydowanie minimalizuje nadmiarowy kod tylko do wywołania bindowania, a co najważniejsze daje mi system delegatów oparty na wariancie, którego mogę używać wszędzie.

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget); 
} 

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1); 
} 

template<class CALLBACK_TARGET_CLASS, typename RETURN_TYPE, typename P0, typename P1> 
std::function<RETURN_TYPE()> BindFunction(RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(P0, P1), CALLBACK_TARGET_CLASS* callbackTarget) 
{ 
    return std::bind(memberFunction, callbackTarget, std::placeholders::_1, std::placeholders::_2); 
} 



template<typename RETURNTYPE, typename... ARGS> 
struct Delegate 
{ 
    std::function<RETURN_TYPE (ARGS...)> callbackFunction; 

    template<class CALLBACK_TARGET_CLASS> 
    void Bind(CALLBACK_TARGET_CLASS* callbackTarget, RETURN_TYPE (CALLBACK_TARGET_CLASS::*memberFunction)(ARGS...)) 
    { 
     callbackFunction = BindFunction<CALLBACK_TARGET_CLASS, RETURN_TYPE, ARGS...>(memberFunction, callbackTarget); 
    } 

    void Callback(ARGS... params) 
    { 
     callbackFunction(params...); 
    } 
}; 

Wykorzystanie kończy nam patrząc tak ..

class Foo 
{ 
public: 
    void Bar(int x); 
} 

Foo foo; 
Delegate<void, int> myDelegate; 

myDelegate.Bind(&foo, &Foo::Bar); 

myDelegate.Callback(3); 
0

Korzystanie _1, _2, ... nie jest możliwe bezpośrednio ze zmiennej liczbie argumentów szablonu. Zamiast tego należy użyć makr ekspansywnych.

Można jednak owijać symbole zastępcze w fabryce szablonów, aby uzyskać _1 z argumentem szablonu 1, _2 dla 2 itd. ...

Wdrożenia takie jak gcc/MSVC już określić zastępcze w szablonie struct (odpowiednio std :: _ zastępczy i std :: _ Ph), dzięki czemu można określić you fabrycznie w ten sposób:

struct ph_factory { 
    template<size_t holder> 
    static std::_Placeholder<holder> make_ph() { 
     return std::_Placeholder<holder>(); 
    } 
}; 

to zdefiniowane, można rozszerzyć paczka parametr ze wszystkimi zastępcze chcesz:

struct tester { 

    template<size_t ... holders> 
    void test(int val) { 
     auto callable = std::bind(&tester::call, this, val, ph_factory::make_ph<holders>()...); 
     callable('a', 42, 'c'); 
    } 

    void call(int v1, char c1, int v2, char c2) { 
     cout << "calling :" << v1 << " " << c1 << " " << v2 << " " << c2 << endl; 
    } 
}; 

więc poniższy kod wyświetli "numerem: 10 c 42 a"

int main() { 
    tester t; 
    t.test<3,2,1>(10); 
} 

Korzystanie z takich sztuczek, jak make_indice, da ci możliwość osiągnięcia pierwotnego celu.

+2

Nigdy nie polegaj na '_Names', są one całkowicie prywatne do implementacji i nie masz powodu, aby kiedykolwiek o nich myśleć. Są lepsze sposoby, z których jeden polega na tym, że umieszczasz wszystkie symbole zastępcze w 'krotce' i' get 'przy pomocy rozszerzenia paczki. Drugim jest to, że rejestrujesz swój własny symbol zastępczy (standard zapewnia cechę 'is_placeholder' z tego powodu, którą możesz wyspecjalizować. – Xeo

Powiązane problemy