Coś, co ostatnio często robię, to deklarowanie typów definicji odpowiednich dla określonej klasy wewnątrz tej klasy, tj
class Lorem
{
typedef boost::shared_ptr<Lorem> ptr;
typedef std::vector<Lorem::ptr> vector;
//
// ...
//
};
Te typy są następnie używane w innym miejscu w kodzie:
Lorem::vector lorems;
Lorem::ptr lorem( new Lorem() );
lorems.push_back( lorem );
Powody, dla których to lubię:
- Zmniejsza hałas wprowadzany przez szablony klas,
std::vector<Lorem>
staje sięLorem::vector
itp. - Służy jako deklaracja intencji - w powyższym przykładzie klasa Lorem ma być odniesieniem liczonym przez
boost::shared_ptr
i przechowywanym w wektorze. - Pozwala to na zmianę implementacji - tj. Gdyby Lorem wymagał zmiany, aby inwazyjne zliczanie referencji (przez
boost::intrusive_ptr
) na późniejszym etapie, miałoby to minimalny wpływ na kod. - Myślę, że wygląda „ładniej” i jest prawdopodobnie łatwiejszy do odczytania.
Powody, dla których tego nie lubię:
- Czasami występują problemy z zależnościami - jeśli chcesz osadzić, powiedzmy, a
Lorem::vector
w innej klasie, ale potrzebujesz (lub chcesz) przekazać dalej deklarację Lorem (w przeciwieństwie do wprowadzania zależności od jej pliku nagłówkowego), w końcu będziesz musiał użyć jawne typy (np.boost::shared_ptr<Lorem>
zamiastLorem::ptr
), co jest trochę niespójne. - Może nie jest to zbyt częste i przez to trudniejsze do zrozumienia?
Staram się być obiektywny w swoim stylu kodowania, więc dobrze byłoby poznać inne opinie na jego temat, abym mógł trochę przeanalizować swoje myślenie.
c++
coding-style
typedef
Will Baker
źródło
źródło
Właśnie tego nie robi.
Jeśli widzę w kodzie „Foo :: Ptr”, nie mam absolutnie pojęcia, czy jest to shared_ptr czy Foo * (w STL są :: pointer typedefs, które są T *, pamiętaj), czy cokolwiek innego. Esp. jeśli jest to wskaźnik współdzielony, nie dostarczam w ogóle typedef, ale zachowuję użycie shared_ptr jawnie w kodzie.
Właściwie rzadko używam czcionek poza metaprogramowaniem szablonów.
Projekt STL z pojęciami zdefiniowanymi w kategoriach funkcji składowych i zagnieżdżonych typówef jest historyczną ślepą uliczką, nowoczesne biblioteki szablonów używają bezpłatnych funkcji i klas cech (por. Boost.Graph), ponieważ nie wykluczają one wbudowanych typów z modelowanie koncepcji i ponieważ ułatwia adaptację typów, które nie zostały zaprojektowane z myślą o koncepcjach określonych bibliotek szablonów.
Nie używaj STL jako powodu do popełnienia tych samych błędów.
źródło
std::allocator_traits<Alloc>
klasę ... nie musisz jej specjalizować dla każdego pojedynczego alokatora, który piszesz, ponieważ po prostu pożycza typy bezpośrednio zAlloc
.Alloc
autorowi nie jest trudniej wyspecjalizować sięstd::allocator_traits<>
w nowym typie, niż dodać potrzebne typy. Zredagowałem również odpowiedź, ponieważ moja pełna odpowiedź nie mieściła się w komentarzu.allocator_traits
próbą utworzenia niestandardowego przydzielania, nie muszę męczyć się z piętnastu członków klasy cechami ... wszystko, co musisz zrobić, to powiedziećtypedef Blah value_type;
i zapewnić odpowiednie funkcje składowe, a domyślnymallocator_traits
będzie dowiedzieć się odpoczynek. Spójrzmy dalej na przykład Boost.Graph. Tak, intensywnie wykorzystuje klasę cech ... ale domyślna implementacjagraph_traits<G>
po prostu pytaG
o własne wewnętrzne typy definicji.iterator_traits
więc klasę, dzięki której ogólne algorytmy mogą łatwo wyszukiwać odpowiednie informacje. Co znowu, domyślnie wysyła zapytanie do iteratora o jego własne informacje. Krótko mówiąc, cechy i typy wewnętrzne prawie się nie wykluczają ... wspierają się nawzajem.iterator_traits
stało się konieczne, ponieważT*
powinien być modelemRandomAccessIterator
, ale nie możesz umieścić wymaganych czcionek wT*
. Kiedy już to zrobiliśmyiterator_traits
, zagnieżdżone typy stały się zbędne i żałuję, że nie zostały usunięte tam i wtedy. Z tego samego powodu (niemożność dodania wewnętrznych typów czcionek )T[N]
nie modelujeSequence
koncepcji STL i potrzebujesz kludges, takich jakstd::array<T,N>
. Boost.Range pokazuje, jak można zdefiniować nowoczesną koncepcję Sequence, któraT[N]
może modelować, ponieważ nie wymaga zagnieżdżonych typów definicji ani funkcji składowych.Typedef to te, na których projekt oparty na zasadach i cechy zostały zbudowane w C ++, więc moc programowania ogólnego w C ++ wynika z samych typedef.
źródło
Typdefy są zdecydowanie w dobrym stylu. Wszystkie twoje „powody, które lubię” są dobre i poprawne.
O problemach, które masz z tym. Cóż, deklaracja naprzód nie jest świętym Graalem. Możesz po prostu zaprojektować swój kod, aby uniknąć wielopoziomowych zależności.
Możesz przenieść typedef poza klasę, ale Class :: ptr jest o wiele ładniejszy niż ClassPtr, że nie robię tego. To jest jak z przestrzeniami nazw, jak dla mnie - wszystko pozostaje połączone w zakresie.
Czasami to robiłem
Może to być ustawienie domyślne dla wszystkich klas domen i z pewną specjalizacją dla niektórych.
źródło
STL robi tego typu rzeczy przez cały czas - typedefs są częścią interfejsu wielu klas w STL.
to wszystkie typy definicji, które są częścią interfejsu różnych klas szablonów STL.
źródło
Kolejny głos za dobrym pomysłem. Zacząłem to robić, pisząc symulację, która miała być wydajna zarówno w czasie, jak i przestrzeni. Wszystkie typy wartości miały definicję typu Ptr, która zaczynała się jako wspólny wskaźnik doładowania. Następnie wykonałem pewne profilowanie i zmieniłem niektóre z nich na natrętny wskaźnik doładowania bez konieczności zmiany kodu, w którym te obiekty były używane.
Zwróć uwagę, że działa to tylko wtedy, gdy wiesz, gdzie będą używane klasy i że wszystkie zastosowania mają takie same wymagania. Nie użyłbym tego na przykład w kodzie biblioteki, ponieważ pisząc bibliotekę nie możesz wiedzieć, w jakim kontekście będzie ona używana.
źródło
Obecnie pracuję nad kodem, który intensywnie wykorzystuje tego typu typy. Jak dotąd to jest w porządku.
Ale zauważyłem, że dość często istnieją iteracyjne typy typów, definicje są podzielone na kilka klas i nigdy tak naprawdę nie wiesz, z jakim typem masz do czynienia. Moim zadaniem jest podsumowanie rozmiaru niektórych złożonych struktur danych ukrytych za tymi typami czcionek - więc nie mogę polegać na istniejących interfejsach. W połączeniu z trzema do sześciu poziomami zagnieżdżonych przestrzeni nazw i wtedy staje się to mylące.
Dlatego przed ich użyciem należy wziąć pod uwagę kilka punktów
źródło
Polecam przenieść te typy definicji poza klasę. W ten sposób usuniesz bezpośrednią zależność od współdzielonych klas wskaźników i wektorów i możesz je uwzględnić tylko wtedy, gdy jest to potrzebne. Jeśli nie używasz tych typów w swojej implementacji klasy, uważam, że nie powinny one być wewnętrznymi typedefami.
Powody, dla których to lubisz, są nadal dopasowane, ponieważ są rozwiązywane przez aliasy typu poprzez typedef, a nie przez deklarowanie ich wewnątrz klasy.
źródło
Kiedy typedef jest używany tylko w samej klasie (tj. Jest zadeklarowany jako prywatny), myślę, że to dobry pomysł. Jednak z dokładnie tych powodów, które podasz, nie użyłbym tego, jeśli krój pisma ma być znany poza klasą. W takim przypadku polecam przenieść je poza zajęcia.
źródło