(Uwaga: tuple
i tie
można je pobrać z Boost lub C ++ 11.)
Podczas pisania małych struktur z tylko dwoma elementami, czasami wybieram std::pair
, ponieważ wszystkie ważne rzeczy są już zrobione dla tego typu danych, jak operator<
na przykład porządkowanie ścisłe-słabe .
Wadą są jednak prawie bezużyteczne nazwy zmiennych. Nawet jeśli sam to stworzyłem typedef
, dwa dni później nie pamiętam, co first
i co second
dokładnie było, zwłaszcza jeśli są tego samego typu. Sytuacja jest jeszcze gorsza w przypadku więcej niż dwóch członków, ponieważ zagnieżdżanie się pair
jest do niczego.
Inną opcją jesttuple
, albo z Boost, albo C ++ 11, ale to naprawdę nie wygląda ładniej i wyraźniej. Więc wracam do pisania struktur samodzielnie, włączając wszelkie potrzebne operatory porównania.
Ponieważ szczególnie operator<
może to być dość uciążliwe, pomyślałem o obejściu tego całego bałaganu, polegając tylko na operacjach zdefiniowanych dla tuple
:
Przykład operator<
, np. Dla ścisłego-słabego uporządkowania:
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
Sprawia, że tuple
z T&
referencjami od przekazanych argumentów.)
Edycja : sugestia @DeadMG dotycząca prywatnego dziedziczenia z tuple
nie jest zła, ale ma kilka wad:
- Jeśli operatorzy są wolnostojący (prawdopodobnie przyjaciele), muszę dziedziczyć publicznie
- Dzięki rzutowaniu moje funkcje / operatory (w
operator=
szczególności) można łatwo ominąć - Dzięki
tie
rozwiązaniu mogę pominąć niektórych członków, jeśli nie mają znaczenia przy składaniu zamówienia
Czy są jakieś wady tej implementacji, które muszę wziąć pod uwagę?
tie
nie można jej zastosować do elementów z polami bitowymi.tie(...)
wywołania mają być zduplikowane w różnych operatorach (=, ==, <itd.), Możesz napisać prywatną metodę wbudowaną,make_tuple(...)
aby ją hermetyzować, a następnie wywołać ją z różnych innych miejsc, jak wreturn lhs.make_tuple() < rhs.make_tuple();
(chociaż typ zwracany z ta metoda może być fajna do zadeklarowania!)auto tied() const{ return std::tie(the, members, here); }
Odpowiedzi:
To z pewnością ułatwi napisanie poprawnego operatora niż samodzielne przewijanie. Powiedziałbym, że rozważ inne podejście tylko wtedy, gdy profilowanie pokazuje, że operacja porównania jest czasochłonną częścią aplikacji. W przeciwnym razie łatwość utrzymania tego powinna przeważyć nad ewentualnymi obawami dotyczącymi wydajności.
źródło
tuple<>
nic nieoperator<
będzie żadnych wolniej niż odręczny jeden.Natknąłem się na ten sam problem, a moje rozwiązanie wykorzystuje szablony wariadyczne C ++ 11. Oto kod:
Część .h:
Oraz .cpp dla przypadku podstawowego bez argumentów:
Teraz twój przykład staje się:
źródło
Moim zdaniem nadal nie rozwiązujesz tego samego problemu, co
std::tuple
rozwiązania - mianowicie musisz wiedzieć zarówno ile, jak i nazwę każdej zmiennej składowej, powielasz ją dwukrotnie w funkcji. Możesz zdecydować się naprivate
dziedziczenie.Na początku takie podejście jest trochę bardziej kłopotliwe, ale utrzymujesz zmienne i nazwy tylko w jednym miejscu, a nie w każdym miejscu dla każdego operatora, którego chcesz przeciążać.
źródło
T& one_member(){ return std::get<0>(*this); }
itp.? Ale czy nie wymagałoby to ode mnie zapewnienia takiej metody dla każdego „elementu członkowskiego”, który mam, w tym przeciążeń dla wersji stałej i innej niż stała?Jeśli planujesz użyć więcej niż jednego przeciążenia operatora lub więcej metod z krotki, polecam utworzenie krotki jako elementu członkowskiego klasy lub pochodnej z krotki. W przeciwnym razie to, co robisz, to dużo więcej pracy. Decydując się między nimi, ważne pytanie, na które należy odpowiedzieć, brzmi: Czy chcesz, aby Twoja klasa była krotką? Jeśli nie, polecam zawarcie krotki i ograniczenie interfejsu za pomocą delegowania.
Możesz utworzyć metody dostępu, aby „zmienić nazwę” członków krotki.
źródło
operator<
stosującstd::tie
rozsądne?” Nie rozumiem, jak ta odpowiedź odnosi się do tego pytania.