"Auspacken", ein Tupel zu nennen, eine matching-Funktion Zeiger
Ich versuche zu speichern in einer std::tuple
eine unterschiedliche Anzahl von Werten, die später verwendet werden als Argumente für einen Aufruf einer Funktion, Zeiger mit dem gespeicherten Typen.
Habe ich ein Vereinfachtes Beispiel zeigt das problem, das ich bin kämpfen, um Sie zu lösen:
#include <iostream>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
void delayed_dispatch() {
//How can I "unpack" params to call func?
func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
//But I *really* don't want to write 20 versions of dispatch so I'd rather
//write something like:
func(params...); //Not legal
}
};
int main() {
int a=666;
double b = -1.234;
void *c = NULL;
save_it_for_later<int,double,void*> saved = {
std::tuple<int,double,void*>(a,b,c), f};
saved.delayed_dispatch();
}
Normalerweise bei Problemen mit std::tuple
oder variadic templates würde ich schreiben eine andere Vorlage wie template <typename Head, typename ...Tail>
rekursiv bewerten alle Typen eins nach dem anderen, aber ich kann nicht sehen, ein Weg, das zu tun, für die Versendung eines Funktionsaufrufs.
Die eigentliche motivation für dieses ist etwas komplexer und es ist meist nur eine Lernübung sowieso. Sie können davon ausgehen, dass ich übergab das Tupel, das durch den Vertrag von einer anderen Schnittstelle, also können nicht geändert werden, aber dass der Wunsch, entpacken Sie es in einen Aufruf der Funktion ist von mir. Diese Regeln mit std::bind
als eine billige Art und Weise zu umgehen, das zugrunde liegende problem.
Was ist eine saubere Art der Versendung der Anruf mit der std::tuple
oder eine alternative der bessere Weg, um die gleiche Netto-Ergebnis von Speicherung/Weiterleitung einige Werte und eine Funktion Zeiger bis zu einem beliebigen zukünftigen Zeitpunkt?
auto saved = std::bind(f, a, b, c);
... später dann einfach anrufen saved()
?Nicht immer mein interface zu Steuern. Ich erhalten ein Tupel, das durch den Vertrag von jemand anders und wollen die Dinge mit zu tun es anschließend.
InformationsquelleAutor Flexo | 2011-10-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Müssen Sie erstellen Sie ein parameter-pack von zahlen und entpacken Sie Sie,
+1 unter der Annahme, dass es funktioniert... (oops, packte ich die "Werke")
Johannes, ich merke Ihr seit 2+ Jahren, seit Sie dieses geschrieben, aber eine Sache, die ich habe Mühe mit der
struct gens
generische definition (der eine, erbt von einer erweitert Ableitung der sagte dasselbe). Ich sehe es schließlich trifft die Spezialisierung mit 0. Wenn die Stimmung zu Ihnen passt und Sie haben die freie Zyklen, wenn Sie erweitern können, und wie es verwertet wird, für diese, würde ich auf ewig dankbar sein. Und ich wünschte, ich könnte die up-vote dies hundert mal. Ich habe mehr Spaß beim spielen mit Tangenten aus diesem code. Danke.Was es tut, ist, erzeugen eine Art
seq<0, 1, .., N-1>
. Wie es funktioniert:gens<5>: gens<4, 4>: gens<3, 3, 4>: gens<2, 2, 3, 4> : gens<1, 1, 2, 3, 4> : gens<0, 0, 1, 2, 3, 4>
. Die Letzte Art ist darauf spezialisiert, erstellenseq<0, 1, 2, 3, 4>
. Ziemlich cleveren trick.Es lohnt sich, echo-Walter ' s Antwort und die Kommentare darauf: folk brauchen nicht zu erfinden, Ihre eigenen Räder mehr. Die Erzeugung einer Sequenz war so verbreitet, dass es standardisiert in C++14 als
std::integer_sequence<T, N>
und die Spezialisierung davon fürstd::size_t
,std::index_sequence<N>
- plus Ihre zugehörigen Hilfsfunktionenstd::make_in(teger|dex)_sequence<>()
undstd::index_sequence_for<Ts...>()
. Und in C++17 es gibt eine Menge andere gute Dinge integriert in die Bibliothek - insbesondere einschließlichstd::apply
undstd::make_from_tuple
, die behandeln würden, die Auspacken und Aufruf bitsInformationsquelleAutor Johannes Schaub - litb
Dies ist eine komplette kompilierbare version von Johanne Lösung zu awoodland Frage, in der Hoffnung, es kann nützlich sein, um jemanden. Getestet wurde dies mit einem snapshot von g++ 4.7 unter Debian squeeze.
Kann man die folgenden SConstruct-Datei
Auf meinem Rechner, das gibt
Ich denke, Sie werden nicht benötigt. Ich habe vergessen, warum ich das Hinzugefügt; es ist schon fast drei Jahre. Aber ich nehme an, zu zeigen, dass die Instanziierung funktioniert.
InformationsquelleAutor Faheem Mitha
Hier ist eine C++ - 14-Lösung.
Diese muss noch eine Hilfsfunktion (
call_func
). Da dies eine gängige Redewendung, die vielleicht den standard unterstützen sollte, es direkt alsstd::call
mit möglichen UmsetzungDann unsere verspätete Versendung wird
std::call
. C++14 ist chaotisch zoo voninteger_sequence
undindex_sequence
Helfer-Typen ist hier erklärt: en.cppreference.com/w/cpp/utility/integer_sequence Beachten Sie die auffällige Abwesenheit vonstd::make_index_sequence(Args...)
, das ist der Grund, warum Walter war gezwungen, in die clunkier syntaxstd::index_sequence_for<Args...>{}
.Und anscheinend gestimmt in C++17 seit 3/2016 als std::apply(func, tup): en.cppreference.com/w/cpp/utility/apply
InformationsquelleAutor Walter
C++17 Lösung ist einfach zu bedienen
std::apply
:Fühlte nur, dass angegeben werden sollte, sobald in einer Antwort in diesem thread (nachdem es erschienen bereits in einem der Kommentare).
Den grundlegenden C++14 Lösung fehlt noch in diesem thread. EDIT: Nein, es ist tatsächlich es in der Antwort von Walter.
Diese Funktion ist gegeben:
Rufen Sie es mit dem folgenden Codeausschnitt:
Beispiel:
DEMO
http://coliru.stacked-crooked.com/a/8ea8bcc878efc3cb
wollen Sie so etwas wie dieses, hier?
danke, ich habe 2 Fragen: 1. Warum kann ich nicht den pass
std::make_unique
direkt? Braucht es konkrete Funktion Instanz? 2. Warumstd::move(ts)...
wenn wir ändern können[](auto... ts)
zu[](auto&&... ts)
?1. funktioniert nicht aus den Signaturen: Ihr
std::make_unique
erwartet ein Tupel, ein Tupel erstellt werden können von einer ausgepackt Tupel nur über einen anderen Aufrufstd::make_tuple
. Dies ist, was ich getan habe, in der der lambda-Ausdruck (obwohl es ist hoch redundant, da kann man auch einfach kopieren der Tupel in die einzigartige Zeiger, ohne irgendeinen nutzen fürcall
).2. Sie konnten den zweiten, aber ich vermute, Sie möchten die Arbeit mit Kopien ... es gibt kaum eine Notwendigkeit für eine besitzende Zeiger von Referenzen. (Sie können auch diese mit Ihrem zweiten version mit etwas wie
std::make_tuple<std::decay_t<decltype(ts)...>>(std::forward<decltype(ts)>(ts) ...)
als Gegenleistung, aber das ist noch viel mehr zu schreiben.)InformationsquelleAutor davidhigh
Dies ist ein wenig kompliziert zu erreichen (auch wenn es möglich ist). Ich rate Ihnen, verwenden Sie eine Bibliothek, wo dies bereits umgesetzt wird, nämlich Boost.Fusion (die aufrufen - Funktion). Als bonus -, Boost-Fusion arbeitet mit C++03-Compiler als gut.
InformationsquelleAutor Karel Petranek
c++14 - Lösung. Zunächst einige utility-boilerplate:
Diese können Sie aufrufen, einen lambda-Ausdruck mit einer Reihe von compile-time-zahlen.
und wir sind fertig.
index_upto
undindex_over
lassen Sie arbeiten mit parameter packs die zimmerreserviereung, ohne das Sie zum generieren eines neuen externen überlastungen.Natürlich in c++ - 17 die Sie gerade
Wenn wir nun, dass wie in c++14, können wir schreiben:
relativ leicht und bekommen Sie den Reiniger c++ - 17 - syntax bereit zu versenden.
ersetzen Sie einfach
notstd
mitstd
wenn Ihr compiler upgrades und bob ist dein Onkel.std::apply
<- Musik in meinen OhrenNur ein bisschen kürzer als
index_upto
und weniger flexibel. 😉 Versuchen Sie den Aufruffunc
mit den Argumenten, die rückwärts mitindex_upto
undstd::apply
beziehungsweise. Zugegeben, wer zum Teufel will zum aufrufen einer Funktion aus einem Tupel rückwärts.Kleiner Punkt:
std::tuple_size_v
ist C++17, also für den C++14-Lösung, die müsste ersetzt werden durchtypename std::tuple_size<foo>::value
Ich hoffe
value
ist nicht ein Typ. Aber fest irgendwie.Nein, es ist
sizeof...(Types)
. Ich mag deine Lösung ohne dietypename
.InformationsquelleAutor Yakk - Adam Nevraumont
Denken über das problem, das einige mehr auf der Grundlage der Antwort, die ich gefunden habe, einen anderen Weg zur Lösung des gleichen Problems:
Erfordert die änderung der Umsetzung von
delayed_dispatch()
:Dies funktioniert, indem Sie rekursiv die Umwandlung der
std::tuple
zu einem parameter-pack in seinem eigenen Recht.call_or_recurse
benötigt wird als eine Spezialisierung zu beenden die Rekursion mit der realen nennen, die nur entpackt den ausgefüllten parameter pack.Ich bin mir nicht sicher, das ist eh eine "bessere" Lösung, aber es ist eine Möglichkeit, darüber nachzudenken und es zu lösen.
Als eine weitere alternative Lösung, die Sie verwenden können
enable_if
zu bilden, etwas, was wohl einfacher ist, als meine bisherige Lösung:Den ersten überlast-nur nimmt man die Argumentation aus dem Tupel und setzt es in einen parameter packen. Die zweite überladung nimmt eine entsprechende parameter-pack und dann macht der echte Anruf, mit der ersten überlast deaktiviert in der eine und einzige Fall, wo die zweite wäre lebensfähig.
rein von der Lern-Perspektive, wäre ich daran interessiert, dass alternative Lösungen nicht einkochen, einige schrecklich hack botching der stack-pointer (oder ähnlich Aufrufkonvention bestimmten tricks).
InformationsquelleAutor Flexo
Meine variation der Lösung von Johannes mit der C++14 std::index_sequence (und Funktion Rückgabe-Typ als template-parameter RetT):
Ich denke, Vorlagen bekam viel besser und verständlicher mit C++11 und 14. Vor ein paar Jahren, als ich sah, was-boost, mit Vorlagen unter der Haube, habe ich mich wirklich entmutigt. Ich Stimme zu, dass die Entwicklung von guten Vorlagen ist deutlich schwieriger als nur mit Ihnen.
Erstens, in Bezug auf die Vorlage Komplexität, das ist nichts. Zweitens, die meisten Helfer Vorlagen sind eine Investition für eine tonne eingesparte Zeit beim instanziieren Sie später. Zu guter Letzt, was würden Sie lieber auf nicht haben die Fähigkeit zu tun, was Vorlagen können Sie tun? Sie konnte einfach nicht verwenden, und sich nicht einfach irrelevante Kommentare, die scheinen, zu sein, die Polizeiarbeit in anderen Programmierer.
InformationsquelleAutor schwart