Dlaczego nikt nie używa krotek w C ++, ani w Boost Tuple Library, ani w bibliotece standardowej dla TR1? Przeczytałem dużo kodu C ++ i bardzo rzadko widzę użycie krotek, ale często widzę wiele miejsc, w których krotki rozwiązałyby wiele problemów (zwykle zwracając wiele wartości z funkcji).
Krotki pozwalają robić różne fajne rzeczy, takie jak ta:
tie(a,b) = make_tuple(b,a); //swap a and b
To z pewnością lepsze niż to:
temp=a;
a=b;
b=temp;
Oczywiście zawsze możesz to zrobić:
swap(a,b);
Ale co, jeśli chcesz obrócić trzy wartości? Możesz to zrobić za pomocą krotek:
tie(a,b,c) = make_tuple(b,c,a);
Krotki znacznie ułatwiają również zwracanie wielu zmiennych z funkcji, co jest prawdopodobnie znacznie częstszym przypadkiem niż zamiana wartości. Używanie odwołań do zwracania wartości z pewnością nie jest zbyt eleganckie.
Czy są jakieś duże wady krotki, o których nie myślę? Jeśli nie, dlaczego są rzadko używane? Czy są wolniejsze? A może po prostu ludzie nie są do nich przyzwyczajeni? Czy warto używać krotek?
a = a ^ b; b = a ^ b; a = a ^ b;
Odpowiedzi:
Ponieważ nie jest jeszcze standardem. Wszystko, co niestandardowe, wiąże się z dużo większą przeszkodą. Kawałki Boost stały się popularne, ponieważ programiści ich domagali się. (na myśl przychodzi hash_map). Ale chociaż krotka jest przydatna, nie jest to tak przytłaczająca i wyraźna wygrana, że ludzie się nią przejmują.
źródło
Cyniczną odpowiedzią jest to, że wiele osób programuje w C ++, ale nie rozumie i / lub nie korzysta z funkcjonalności wyższego poziomu. Czasami dzieje się tak dlatego, że im nie wolno, ale wielu po prostu nie próbuje (a nawet nie rozumie).
Jako przykład bez wspomagania: ilu ludzi korzysta z funkcji znajdujących się w
<algorithm>
?Innymi słowy, wielu programistów C ++ jest po prostu programistami C używającymi kompilatorów C ++ i być może
std::vector
istd::list
. Jest to jeden z powodów, dla których stosowanieboost::tuple
nie jest bardziej powszechne.źródło
Składnia krotki w C ++ może być nieco bardziej szczegółowa, niż by tego chciała większość ludzi.
Rozważać:
Więc jeśli chcesz szeroko korzystać z krotek, albo wszędzie dostaniesz kroje czcionek, albo wszędzie otrzymujesz irytująco długie nazwy typów. Lubię krotki. Używam ich w razie potrzeby. Ale zwykle ogranicza się to do kilku sytuacji, takich jak indeks N-elementowy lub użycie multimap do powiązania par iteratorów zakresu. Zwykle ma to bardzo ograniczony zakres.
W porównaniu z czymś takim jak Haskell czy Python wygląda to bardzo brzydko i hackowo. Kiedy pojawi się C ++ 0x i otrzymamy słowo kluczowe „auto”, krotki słów kluczowych zaczną wyglądać o wiele bardziej atrakcyjnie.
Użyteczność krotek jest odwrotnie proporcjonalna do liczby naciśnięć klawiszy wymaganych do ich zadeklarowania, spakowania i rozpakowania.
źródło
Dla mnie to nawyk, bez dwóch zdań: krotki nie rozwiązują dla mnie żadnych nowych problemów, tylko kilka, które już dobrze sobie radzę. Zamiana wartości nadal wydaje się łatwiejsza w staromodny sposób - i, co ważniejsze, tak naprawdę nie myślę o tym, jak zamienić „lepiej”. Jest wystarczająco dobry, jak jest.
Osobiście nie uważam, że krotki są świetnym rozwiązaniem zwracania wielu wartości - brzmi to jak praca dla
struct
s.źródło
Ale co, jeśli chcesz obrócić trzy wartości?
OK, więc przy 4 wartościach etc, ostatecznie n-tuple staje się mniejszym kodem niż n-1 swapów. Z domyślną zamianą powoduje to przypisanie 6 zamiast 4, które miałbyś, gdybyś sam zaimplementował szablon trzystopniowy, chociaż mam nadzieję, że kompilator rozwiąże to dla prostych typów.
Możesz wymyślić scenariusze, w których zamiany są nieporęczne lub nieodpowiednie, na przykład:
rozpakowanie jest trochę niewygodne.
Chodzi jednak o to, że istnieją znane sposoby radzenia sobie z najczęstszymi sytuacjami, w których krotki są dobre, a zatem nie ma pilnej potrzeby zajmowania się krotkami. Jeśli nic więcej, nie jestem pewien, że:
nie robi 6 kopii, co czyni go całkowicie nieodpowiednim dla niektórych typów (kolekcje są najbardziej oczywiste). Możesz mnie przekonać, że krotki są dobrym pomysłem dla „dużych” typów, mówiąc, że tak nie jest :-)
W przypadku zwracania wielu wartości krotki są idealne, jeśli wartości są niezgodnych typów, ale niektórzy ludzie ich nie lubią, jeśli wywołujący może uzyskać je w złej kolejności. Niektórzy ludzie w ogóle nie lubią wielu zwracanych wartości i nie chcą zachęcać do ich używania, ułatwiając je. Niektórzy ludzie po prostu wolą nazwane struktury dla parametrów wejścia i wyjścia i prawdopodobnie nie można ich przekonać kijem baseballowym do używania krotek. Bez względu na smak.
źródło
Jak wiele osób zauważyło, krotki nie są po prostu tak przydatne, jak inne funkcje.
Zamienianie i obracanie sztuczek to tylko sztuczki. Są całkowicie mylące dla tych, którzy wcześniej ich nie widzieli, a ponieważ to prawie wszyscy, te sztuczki są po prostu kiepską praktyką inżynierii oprogramowania.
Zwracanie wielu wartości przy użyciu krotek jest znacznie mniej dokumentujące niż alternatywy - zwracanie nazwanych typów lub używanie nazwanych odwołań. Bez tego samodokumentowania łatwo jest pomylić kolejność zwracanych wartości, jeśli są one wzajemnie wymienialne i nie być mądrzejszym.
źródło
Nie każdy może korzystać z boostu, a TR1 nie jest jeszcze powszechnie dostępny.
źródło
W przypadku używania C ++ w systemach wbudowanych pobieranie bibliotek Boost staje się skomplikowane. Łączą się ze sobą, więc rozmiar biblioteki rośnie. Zwracasz struktury danych lub używasz przekazywania parametrów zamiast krotek. Podczas zwracania krotek w Pythonie struktura danych jest w kolejności, a typ zwracanych wartości po prostu nie jest jawny.
źródło
Rzadko je widzisz, ponieważ dobrze zaprojektowany kod zwykle ich nie potrzebuje - nie ma zbyt wielu przypadków na wolności, w których użycie struktury anonimowej jest lepsze niż użycie nazwanej. Ponieważ cała krotka naprawdę reprezentuje jest strukturą anonimową, większość programistów w większości sytuacji po prostu pasuje do prawdziwej rzeczy.
Powiedzmy, że mamy funkcję „f”, w której zwrot krotki może mieć sens. Z reguły takie funkcje są zwykle na tyle skomplikowane, że mogą zawieść.
Jeśli "f" CAN zawiedzie, potrzebujesz zwrotu statusu - w końcu nie chcesz, aby wywołujący musieli sprawdzać każdy parametr, aby wykryć awarię. „f” prawdopodobnie pasuje do wzorca:
To nie jest ładne, ale spójrz, jak brzydka jest alternatywa. Zauważ, że nadal potrzebuję wartości statusu, ale kod nie jest bardziej czytelny i nie jest krótszy. Prawdopodobnie jest też wolniejszy, ponieważ ponoszę koszt 1 kopii z krotką.
Inny, znaczący minus jest tutaj ukryty - dzięki „ReturnInts” mogę dodać zmianę zwrotu „f”, modyfikując „ReturnInts” BEZ ZMIANY INTERFEJSU „f”. Rozwiązanie krotki nie oferuje tej krytycznej funkcji, co sprawia, że jest gorszą odpowiedzią dla dowolnego kodu biblioteki.
źródło
using std::tuple;
i po prostu używająctuple
w kodzie.tuple
sprawia, że kod jest mniej czytelny, a nie bardziej. Większość kodów w dzisiejszych czasach zawiera bardzo dużą liczbę symboli - zobaczeniestd::tuple
jasno pokazuje, co to jest.Z pewnością krotki mogą być przydatne, ale jak wspomniano, jest trochę nad głową i jedna lub dwie przeszkody, przez które musisz przeskoczyć, zanim będziesz mógł ich naprawdę użyć.
Jeśli Twój program konsekwentnie znajduje miejsca, w których musisz zwrócić wiele wartości lub zamienić kilka wartości, warto skorzystać z trasy krotek, ale czasami po prostu łatwiej jest robić rzeczy w klasyczny sposób.
Ogólnie rzecz biorąc, nie każdy ma już zainstalowany Boost i na pewno nie przechodziłbym przez kłopoty z jego pobieraniem i konfigurowaniem moich katalogów dołączania do pracy z nim tylko dla jego funkcji krotek. Myślę, że przekonasz się, że osoby, które już używają Boost, są bardziej skłonne do znajdowania zastosowań krotek w swoich programach niż użytkownicy, którzy nie korzystają z Boost, a migranci z innych języków (przychodzi na myśl Python) są bardziej skłonni do po prostu zmartwienia z powodu braku krotek w C ++ niż zbadanie metod dodawania obsługi krotek.
źródło
Ponieważ magazyn danych
std::tuple
ma najgorsze cechy zarówno a, jakstruct
i tablicy; cały dostęp jest oparty na n-tej pozycji, ale nie można iterować przez pętlętuple
usingfor
.Jeśli więc elementy w
tuple
są koncepcyjnie tablicą, użyję tablicy, a jeśli koncepcyjnie elementy nie są tablicą, struktura (która ma nazwane elementy) jest łatwiejsza w utrzymaniu. (a.lastname
jest bardziej wyjaśniające niżstd::get<1>(a)
).To pozostawia transformację wspomnianą przez OP jako jedyny realny przypadek użycia krotek.
źródło
Mam wrażenie, że wielu używa Boost.Any i Boost.Variant (z pewną inżynierią) zamiast Boost.Tuple.
źródło