Dies ist eine Fortsetzung meiner vorherigen Frage zu hübsch gedruckten STL-Containern , für die wir eine sehr elegante und vollständig allgemeine Lösung entwickelt haben.
In diesem nächsten Schritt möchte ich das hübsche Drucken std::tuple<Args...>
mit variadischen Vorlagen einschließen (dies ist also ausschließlich C ++ 11). Denn std::pair<S,T>
ich sage einfach
std::ostream & operator<<(std::ostream & o, const std::pair<S,T> & p)
{
return o << "(" << p.first << ", " << p.second << ")";
}
Was ist die analoge Konstruktion zum Drucken eines Tupels?
Ich habe versucht, verschiedene Teile des Vorlagenargumentstapels zu entpacken, Indizes weiterzugeben und mithilfe von SFINAE herauszufinden, wann ich am letzten Element bin, aber ohne Erfolg. Ich werde dich nicht mit meinem kaputten Code belasten. Die Problembeschreibung ist hoffentlich einfach genug. Im Wesentlichen möchte ich folgendes Verhalten:
auto a = std::make_tuple(5, "Hello", -0.1);
std::cout << a << std::endl; // prints: (5, "Hello", -0.1)
Bonuspunkte für die Aufnahme der gleichen Allgemeinheit (char / wchar_t, Paarbegrenzer) wie in der vorherigen Frage!
quelle
Antworten:
Ja, Indizes ~
Live-Beispiel auf Ideone.
Fügen Sie für das Trennzeichen einfach diese Teilspezialisierungen hinzu:
und ändern Sie das
operator<<
undprint_tuple
entsprechend:Und
quelle
TuplePrinter
hat keineoperator<<
.class Tuple
für dieoperator<<
Überlastung verwenden - es würde für alle Dinge ausgewählt werden. Es würde eine Einschränkung erfordern, die irgendwie die Notwendigkeit einer Art variadischer Argumente impliziert.swallow{(os << get<Is>(t))...};
.Ich habe dies in C ++ 11 (gcc 4.7) gut funktioniert. Ich bin mir sicher, dass ich einige Fallstricke nicht berücksichtigt habe, aber ich denke, der Code ist einfach zu lesen und nicht kompliziert. Das einzige, was seltsam sein kann, ist die "guard" -Struktur tuple_printer, die sicherstellt, dass wir beenden, wenn das letzte Element erreicht ist. Die andere seltsame Sache kann sizeof ... (Typen) sein, die die Anzahl der Typen im Typentyppaket zurückgeben. Es wird verwendet, um den Index des letzten Elements zu bestimmen (Größe ... (Typen) - 1).
quelle
std::make_tuple()
. Aber zum Zeitpunkt des Druckensmain()
gibt es eine Reihe von Fehlern! Gibt es Vorschläge für eine einfachere Art, die Tupel zu drucken?In C ++ 17 können wir dies mit etwas weniger Code erreichen, indem wir Fold-Ausdrücke nutzen , insbesondere eine unäre linke Falte:
Live-Demo- Ausgaben:
gegeben
Erläuterung
Unsere unäre linke Falte hat die Form
Dabei ist
op
in unserem Szenario der Kommaoperator undpack
der Ausdruck, der unser Tupel enthält, in einem nicht erweiterten Kontext wie:Also, wenn ich so ein Tupel habe:
Und a,
std::integer_sequence
deren Werte durch eine Nicht-Typ-Vorlage angegeben werden (siehe obigen Code)Dann der Ausdruck
Wird erweitert in
Welches wird gedruckt
Was grob ist, also müssen wir noch einige Tricks machen, um ein Komma-Trennzeichen hinzuzufügen, das zuerst gedruckt werden soll, es sei denn, es ist das erste Element.
Um dies zu erreichen, ändern wir den zu druckenden
pack
Teil des Falzausdrucks," ,"
wenn der aktuelle IndexI
nicht der erste ist, daher der(I == 0? "" : ", ")
Teil * :Und jetzt werden wir bekommen
Was schöner aussieht (Hinweis: Ich wollte eine ähnliche Ausgabe wie diese Antwort )
* Hinweis: Sie können die Komma-Trennung auf verschiedene Arten durchführen, als ich es am Ende getan habe. Ich zunächst Komma bedingt hinzugefügt , nachdem statt , bevor durch die Prüfung gegen
std::tuple_size<TupType>::value - 1
, aber das war zu lang, so dass ich getestet , anstatt gegensizeof...(I) - 1
, aber am Ende habe ich kopiert Xeo und wir am Ende mit dem, was ich habe.quelle
if constexpr
für den Basisfall verwenden.Ich bin überrascht, dass die Implementierung von cppreference noch nicht hier veröffentlicht wurde, also werde ich es für die Nachwelt tun. Es ist im Dokument versteckt,
std::tuple_cat
daher ist es nicht leicht zu finden. Es verwendet eine Schutzstruktur wie einige der anderen Lösungen hier, aber ich denke, ihre ist letztendlich einfacher und leichter zu befolgen.Und ein Test:
Ausgabe:
Live-Demo
quelle
Basierend auf AndyG-Code für C ++ 17
mit Ausgabe:
quelle
Basierend auf einem Beispiel für die C ++ - Programmiersprache von Bjarne Stroustrup, Seite 817 :
Ausgabe:
quelle
Durch die Nutzung von
std::apply
(C ++ 17) können wir die löschenstd::index_sequence
und eine einzelne Funktion definieren:Oder mit Hilfe eines Stringstreams leicht verschönert:
quelle
Eine andere, ähnlich wie bei @Tony Olsson, einschließlich einer Spezialisierung für das leere Tupel, wie von @Kerrek SB vorgeschlagen.
quelle
Ich mag die Antwort von DarioP, aber Stringstream verwendet Heap. Dies kann vermieden werden:
quelle
Eine Sache, die ich an den vorherigen Antworten, die Fold-Ausdrücke verwenden, nicht mag, ist, dass sie Indexsequenzen oder Flags verwenden, um das erste Element zu verfolgen, was den Vorteil netter sauberer Fold-Ausdrücke weitgehend beseitigt.
Hier ist ein Beispiel, das keine Indizierung benötigt, aber ein ähnliches Ergebnis erzielt. (Nicht so raffiniert wie einige der anderen, aber es könnten weitere hinzugefügt werden.)
Die Technik besteht darin, das zu verwenden, was die Falte Ihnen bereits bietet: einen Sonderfall für ein Element. Das heißt, eine Elementfalte wird nur erweitert
elem[0]
, dann sind 2 Elementeelem[0] + elem[1]
, wo+
eine Operation ausgeführt wird. Was wir wollen, ist, dass ein Element genau dieses Element in den Stream schreibt, und für mehr Elemente dasselbe tun, aber jedes mit einem zusätzlichen Schreibvorgang von "," verbinden. Wenn wir dies also der c ++ - Falte zuordnen, möchten wir, dass jedes Element die Aktion ist, ein Objekt in den Stream zu schreiben. Wir möchten, dass unsere+
Operation darin besteht, zwei Schreibvorgänge mit einem "," - Schreibzugriff zu versehen. Verwandeln Sie also zuerst unsere Tupelsequenz in eine Sequenz von Schreibaktionen, dieCommaJoiner
ich genannt habe, und fügen Sie dann für diese Aktion eine hinzuoperator+
, um zwei Aktionen auf die von uns gewünschte Weise zu verbinden, und fügen Sie dazwischen ein "," hinzu:Ein flüchtiger Blick auf Godbolt deutet darauf hin, dass dies auch recht gut kompiliert werden kann, da alle Thunks-Anrufe abgeflacht sind.
Dies erfordert jedoch eine zweite Überlastung, um mit einem leeren Tupel fertig zu werden.
quelle