(Hinweis: tuple
und tie
kann aus Boost oder C ++ 11 übernommen werden.)
Wenn ich kleine Strukturen mit nur zwei Elementen schreibe, neige ich manchmal dazu, a zu wählen std::pair
, da alle wichtigen Dinge für diesen Datentyp bereits erledigt sind, wie operator<
zum Beispiel für strikt schwache Ordnungen .
Die Nachteile sind jedoch die ziemlich nutzlosen Variablennamen. Selbst wenn ich das selbst geschaffen habe typedef
, werde ich mich 2 Tage später nicht mehr daran erinnern, was first
und was second
genau war, besonders wenn beide vom gleichen Typ sind. Dies wird für mehr als zwei Mitglieder noch schlimmer, da das Verschachteln pair
ziemlich scheiße ist.
Die andere Option dafür ist atuple
, entweder von Boost oder C ++ 11, aber das sieht nicht wirklich schöner und klarer aus. Also schreibe ich die Strukturen wieder selbst, einschließlich aller erforderlichen Vergleichsoperatoren.
Da besonders das operator<
ziemlich umständlich sein kann, dachte ich daran, dieses ganze Durcheinander zu umgehen, indem ich mich nur auf die Operationen stütze, die definiert sind für tuple
:
Beispiel operator<
zB für streng-schwache Ordnung:
bool operator<(MyStruct const& lhs, MyStruct const& rhs){
return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}
( tie
Macht einen tuple
von T&
Referenzen aus den übergebenen Argumenten.)
Bearbeiten : Der Vorschlag von @DeadMG, privat zu erben, tuple
ist nicht schlecht, hat aber einige Nachteile:
- Wenn die Betreiber freistehend sind (möglicherweise Freunde), muss ich öffentlich erben
- Beim Casting können meine Funktionen / Operatoren (
operator=
speziell) leicht umgangen werden - Mit der
tie
Lösung kann ich bestimmte Mitglieder auslassen, wenn sie für die Bestellung keine Rolle spielen
Gibt es irgendwelche Nachteile bei dieser Implementierung, die ich berücksichtigen muss?
tie
sie nicht auf Bitfeldmitglieder angewendet werden kann.tie(...)
Aufrufe in verschiedenen Operatoren (=, ==, <usw.) dupliziert werden sollen, können Sie eine private Inline-Methode schreiben, um diesmake_tuple(...)
zu kapseln, und sie dann von den verschiedenen anderen Stellen aus aufrufen, wie inreturn lhs.make_tuple() < rhs.make_tuple();
(obwohl der Rückgabetyp von Diese Methode könnte Spaß machen zu erklären!)auto tied() const{ return std::tie(the, members, here); }
Antworten:
Dies wird es sicherlich einfacher machen, einen korrekten Operator zu schreiben, als ihn selbst zu rollen. Ich würde sagen, dass Sie einen anderen Ansatz nur in Betracht ziehen, wenn die Profilerstellung zeigt, dass der Vergleichsvorgang ein zeitaufwändiger Teil Ihrer Anwendung ist. Andernfalls sollte die einfache Wartung die möglichen Leistungsprobleme überwiegen.
quelle
tuple<>
demoperator<
es langsamer wäre als ein handgeschriebener.Ich bin auf dasselbe Problem gestoßen und meine Lösung verwendet verschiedene C ++ 11-Vorlagen. Hier kommt der Code:
Der .h Teil:
Und die .cpp für den Basisfall ohne Argumente:
Jetzt wird Ihr Beispiel:
quelle
Meiner Meinung nach
std::tuple
sprechen Sie immer noch nicht das gleiche Problem wie die Lösungen an. Sie müssen nämlich sowohl die Anzahl als auch den Namen jeder Mitgliedsvariablen kennen und diese zweimal in der Funktion duplizieren. Sie könnten sich für dieprivate
Vererbung entscheiden.Dieser Ansatz ist anfangs etwas chaotischer, aber Sie verwalten die Variablen und Namen nur an einem Ort und nicht an jedem Ort für jeden Operator, den Sie überladen möchten.
quelle
T& one_member(){ return std::get<0>(*this); }
etc verwenden? Aber müsste ich dann nicht für jedes "Mitglied", das ich habe, eine solche Methode bereitstellen, einschließlich Überladungen für die const- und non-const-Version?Wenn Sie planen, mehr als eine Operatorüberladung oder mehrere Methoden aus Tupel zu verwenden, würde ich empfehlen, Tupel zu einem Mitglied der Klasse zu machen oder von Tupel abzuleiten. Ansonsten ist das, was Sie tun, viel mehr Arbeit. Wenn zwischen den beiden zu entscheiden, eine wichtige Frage zu beantworten ist: Haben Sie Ihre Klasse wollen sein ein Tupel? Wenn nicht, würde ich empfehlen, ein Tupel zu enthalten und die Schnittstelle durch Delegierung einzuschränken.
Sie können Accessoren erstellen, um die Mitglieder des Tupels "umzubenennen".
quelle
operator<
Ist esstd::tie
vernünftig, meine Klasse zu implementieren ?" Gelesen. Ich verstehe nicht, wie sich diese Antwort auf diese Frage bezieht.