Weiterleiten mehrerer Sätze variadischer ArgumenteC++

Programme in C++. Entwicklerforum
Anonymous
 Weiterleiten mehrerer Sätze variadischer Argumente

Post by Anonymous »

Ich baue einen Container, der als interne Darstellung mehrere Standardcontainer mit jeweils unterschiedlichem Typ verwendet. Ich muss meine Version von emplace(..) codieren und hier bin ich hängengeblieben.
Das ist es, worauf mein Code hinausläuft, mit einer emplace-Funktion, die sich nicht kompilieren lässt, Ihnen aber hoffentlich klar macht, was ich erreichen möchte:

Code: Select all

template 
class MyContainer
{
public:
template 
void emplace(ArgsA&&... argsA, ArgsB&&... argsB)
{
// do custom logic
a_container.emplace_back(std::forward(argsA)...);
b_container.emplace_back(std::forward(argsB)...);
}

private:
std::vector a_container;
std::vector b_container;
};
Wie gesagt, das funktioniert offensichtlich nicht, da der Compiler nicht auf magische Weise entscheiden kann, wo er mit dem Lesen des ersten Argumentpakets aufhört und mit dem zweiten beginnt. Wenn ich solche Probleme sehe, greife ich aufgrund meiner Erfahrung mit Metaprogrammierung sofort nach std::tuple. Wenn es eine bessere Lösung gibt, melden Sie sich bitte an, aber von diesem Punkt an gehe ich davon aus, dass dies der einfachste Weg ist, um voranzukommen.
Mit std::tuple kann das Problem also in ein paar verschiedene Schritte zerlegt werden. In jedem Schritt muss ich sicherstellen, dass die Art (R-Wert vs. L-Wert) der Argumente erhalten bleibt:
  • Argumente an emplace in einem Tupel übergeben
  • das Tupel aus meiner Emplace-Funktion lesen
  • das Tupel entpacken
  • die entpackten Tupelelemente an emplace_back(..) übergeben
Was Punkt 1 betrifft, so hat der Aufrufer möglicherweise bereits ein std::tuple zur Hand, in den meisten Fällen wird er jedoch wahrscheinlich emplace aufrufen und dabei direkt die Parameter verwenden, die letztendlich an die beiden Konstruktoren weitergeleitet werden sollen. Wenn ich mich nicht irre, scheint dies genau das zu sein, wofür std::forward_as_tuple erstellt wurde. Wenn ja, würde ich es als erledigt betrachten.
Punkt 2. bringt ein wenig Unannehmlichkeiten mit sich. Das heißt, emplace so umzuschreiben, dass es std::tuple:
akzeptiert

Code: Select all

template 
void emplace(std::tuple tupleA, std::tuple tupleB)
Leider können diese variablen ArgsA und ArgsB keine Weiterleitungsreferenzen sein, da sie nicht direkt aus der Natur von tupleA und tupleB abgeleitet werden, sondern aus ihren Typen. Ich muss also bedenken, dass es sich sowohl um R-Wert- als auch um L-Wert-Referenzen handeln kann, und das bereinigen, wenn ich sie weiterleite.
Außerdem denke ich, dass die Art und Weise, wie wir std::tuple weitergeben, zu einem seltsamen Verhalten führen kann. Oben habe ich eine „Lazy-Version“ geschrieben, die std::tuple per Kopie übernimmt, aber meistens, wenn ich einen Container schreibe, bevorzuge ich, wie auch der Standard, die Verwendung sowohl einer const std::tuple&- als auch einer std::tuple&&-Version für maximale Flexibilität. In diesem Fall wird die Version „const std::tuple&“ dazu führen, dass „std::get“ aufgrund von Referenz-Reduzierungsregeln nur die L-Werte-Version unserer Argumente extrahiert, was den Punkt zunichte macht. Deshalb denke ich darüber nach, nur std::tuple&& zu schreiben und (vielleicht) die Kopieversion beizubehalten.
Punkte 3. und 4. sind die schwierigsten. Ich schätze, ich muss sie gemeinsam lösen, und ich bin ziemlich überrascht, dass der Standard, soweit ich weiß, std::forward_as_tuple anbietet, aber nicht die umgekehrte Operation. Hier gibt es ein subtiles Problem, das die einfache Lösung der Weiterleitung mit Code wie diesem verhindert:

Code: Select all

template 
void emplace(std::tuple tupleA, std::tuple tupleB)
{
// do custom logic
a_container.emplace_back(std::forward(std::get(tupleA))...);
...
Dies bricht völlig zusammen, wenn Sie wiederholte Typen im std::tuple haben. Wir müssen also Indexzugriff verwenden und meine bisher beste Idee ist, einen std::invoke-Wrapper zu schreiben, der eine std::integer_sequence verwendet, um das std::tuple zu entpacken, aber das ist nur eine Intuition und ich muss die Details ausarbeiten. Wie gesagt und oben gezeigt, muss ich in all diesem Chaos immer noch daran denken, Referenzen von den Typen zu entfernen, aus denen das std::tuple besteht, um die entsprechenden Argumente perfekt weiterzuleiten.
Ich suche insbesondere nach einfacheren Lösungen für die Punkte 3. und 4.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post