2013-03-21 11 views
14
speichern

Im Moment Ich habe Probleme beim Versuch, einen Parameter Pack zu speichern, ist dies Beispielcode des Designs:C++ einen Parameter Pack als Variable

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)...); 
} 

Dies ist ein Beispiel für alles beteiligt für das Problem, ich muss die Argumente für später in meiner Nest-Struktur aufrufen. Auch, wenn Sie eine Lösung haben, um es zu speichern, aber um es anders zu setzen, bitte informieren Sie mich auch darüber. Vielen Dank.

+2

'std :: tuple ' - auch 'std :: bind' und 'std :: function' und all das lustige Zeug. – Xeo

Antwort

17

Sie müssen ::std::tuple<Args...> verwenden, um es zu speichern. Aber dann ist die Frage, wie man es auspackt, wenn Sie es brauchen. Dazu müssen Sie eine Technik namens "Indizes" verwenden.

Also, hier ist ein Link zu einem Ort, wo ich ungefähr getan habe, was Sie tun möchten. Die relevanteste Klasse hier, die eine Art Herzstück ist, ist suspended_call.

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

In nur ein bisschen, werde ich die wichtigsten Bits extrahieren und sie in Bezug auf den Code setzen.

This line:

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

speichert die Argumente in ein Tupel. Ich habe ::std::move dort verwendet, und ich denke, das ist das Richtige zu tun. Aber es ist möglich, dass ich falsch liege und ich sollte ::std::forward verwenden. Ich war nie klar über den genauen Unterschied, abgesehen von der Signalabsicht.

Der Code, der den Aufruf mit den gespeicherten Argumenten tatsächlich ausführt, kann here gefunden werden. Jetzt ist dieser Code ziemlich genau, was genau ich mache. Das Bit, das den Indextrick implementiert, beinhaltet das Erstellen eines Satzes von Ganzzahlen, die den Indizes zugeordnet werden, die als Argumente die ::std::get<I> Vorlage verwenden. Sobald Sie dieses Paket mit ganzen Zahlen haben, können Sie es verwenden, um den Aufruf auf zu erweitern, um alle Tupel-Elemente als einzelne Argumente zu erhalten.

Ich werde versuchen, mit dem Code zu entwickeln, die in einer relativ einfachen Art und Weise funktioniert das:

#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)); 
} 

Viele dieser Code entlehnt wurde von this page on the indices trick.

Auch das ist eine Art von Beispiel, das Sie leicht an Ihre spezifische Situation anpassen müssen. Rufen Sie einfach call(nestFunc, saved_args) irgendwo an.

+0

Wie würde dieses Tupel mit (args) gesetzt ...; – Luka

+1

Können Sie mehr über diese "Indices" erfahren? – 0x499602D2

+0

@David: Ja, mehr Beispiele. Du sollst sie haben. Ich musste eigentlich Code schreiben, der das kürzlich gemacht hat. – Omnifarious

4

Ich weiß, es ist schon eine Weile, aber ich hatte ähnliche Bedürfnisse und kam mit dieser Lösung auf, hoffen, dass es jemand hilft:

#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

cleverer Workaround für die wahnsinnig verkrüppelte C++ Pack-Syntax –

+0

Speichern sie alle in einem Lambda statt in einem Tupel sind sehr schlau. – Omnifarious

Verwandte Themen