2013-03-21 23 views
14

W tej chwili mam problemy próbuje zapisać paczkę parametru, to jest przykład kodu projektu:C++ Jak przechowywać paczkę parametr jako zmienną

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    struct nest { 
     Func nestFunc; 
     Args... nestArgs; // I DONT KNOW WHAT TO DO HERE 
     void setup(Func func, Args... args) { 
      nestFunc = func; 
      nestArgs = (args)...; // SO I CAN SET IT HERE 
     } 
     // Later I will forward this and run the function with its arguments 
     unsigned process() { 
      nestFunc(std::forward<Args>(nestArgs)...); // USE IT HERE 
      return 0; 
     } 
    }; 
    nest* myNest; 
    myNest->setup(func, (args)...); 
} 

ten jest przykładem wszystkiego zaangażowany do problem, muszę przechowywać argumenty dla później wywoływać w mojej strukturze gniazda. Jeśli masz rozwiązanie do przechowywania, ale ustawienie jest inne niż moje, poinformuj mnie również o tym. Dzięki.

+2

'std :: krotki ' - również, 'std :: bind' i 'std :: function' i wszystkie fajne rzeczy. – Xeo

Odpowiedz

17

Musisz użyć ::std::tuple<Args...>, aby go zapisać. Ale wtedy pojawia się pytanie, jak rozpakować go, kiedy go potrzebujesz. Do tego trzeba użyć techniki zwanej "indeksami".

Oto link do miejsca, w którym zrobiłem mniej więcej to, co chcesz zrobić. Najważniejszą klasą, która jest tutaj centralna, jest suspended_call.

https://bitbucket.org/omnifarious/sparkles/src/tip/sparkles/deferred.hpp?at=default

W tylko trochę, będę wyodrębnić najistotniejsze kawałki i umieścić je pod względem kodu.

This line:

auto saved_args = ::std::make_tuple(::std::move(args)...); 

oszczędza argumenty na krotki. Użyłem tam ::std::move i uważam, że jest to słuszne. Ale jest możliwe, że się mylę i powinienem użyć ::std::forward. Nigdy nie miałem jasności co do dokładnej różnicy, oprócz zamiaru sygnalizacji.

Kod, który faktycznie wykonuje połączenie z zapisanymi argumentami, można znaleźć pod numerem here. Teraz ten kod jest dość specyficzny dla dokładnie tego, co robię. Bit, który implementuje sztuczkę indeksów, polega na tworzeniu pakietu liczb całkowitych odwzorowującego indeksy, które będą używane jako argumenty szablonu ::std::get<I>. Kiedy już masz ten pakiet liczb całkowitych, możesz użyć go do rozwinięcia połączenia do ::std::get, aby uzyskać wszystkie elementy krotki jako indywidualne argumenty.

Postaram się wymyślić kodu, który robi to w stosunkowo prosty sposób:

#include <tuple> 
#include <cstddef> 
#include <string> 
#include <utility> 

template < ::std::size_t... Indices> 
struct indices {}; 

template < ::std::size_t N, ::std::size_t... Is> 
struct build_indices : build_indices<N-1, N-1, Is...> 
{}; 

template < ::std::size_t... Is> 
struct build_indices<0, Is...> : indices<Is...> 
{}; 

template <typename FuncT, typename ArgTuple, ::std::size_t... Indices> 
auto call(const FuncT &f, ArgTuple &&args, const indices<Indices...> &) 
    -> decltype(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)) 
{ 
    return ::std::move(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)); 
} 

template <typename FuncT, typename ArgTuple> 
auto call(const FuncT &f, ArgTuple &&args) 
    -> decltype(call(f, args, 
         build_indices< ::std::tuple_size<ArgTuple>::value>{})) 
{ 
    const build_indices< ::std::tuple_size<ArgTuple>::value> indices; 

    return ::std::move(call(f, ::std::move(args), indices)); 
} 

int myfunc(::std::string name, const unsigned int foo) 
{ 
    return 0; 
} 

int foo(::std::tuple< ::std::string, const unsigned int> saved_args) 
{ 
    return call(myfunc, ::std::move(saved_args)); 
} 

Dużo tego kodu została zapożyczona z this page on the indices trick.

To także rodzaj próbki, którą trzeba nieco dostosować do swojej konkretnej sytuacji. Zasadniczo, wystarczy zadzwonić pod numer call(nestFunc, saved_args).

+0

Jak ustawić tę krotkę przez (args) ...; – Luka

+1

Czy możesz dokładniej opisać te "wskaźniki"? – 0x499602D2

+0

@David: Tak, więcej przykładów. Otrzymasz je. Musiałem napisać kod, który ostatnio to zrobił. – Omnifarious

4

wiem, że to było trochę czasu, ale miałem podobne potrzeby i wymyślił tego rozwiązania, mam nadzieję, że ktoś pomoże:

#include <functional> 

template<typename Func, typename... Args> 
struct nest { 
    std::function<void()> callBack; 

    void setup(Func func1, Args... args) { 
     callBack = [func1, args...]() 
     { 
      (func1)(args...); 
     }; 
    } 

    unsigned process() { 
     callBack(); 
     return 0; 
    } 
}; 

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    nest<Func, Args...> myNest; 
    myNest.setup(func, args...); 
} 
+0

sprytne obejście dla szalenie okaleczonej składni pakietu C++) –

+0

Przechowywanie ich wszystkie wewnątrz lambda zamiast w krotce są bardzo sprytne. – Omnifarious