2011-02-09 9 views
20

Zastanawiam się trochę nad tym biznesem szablonowym.Jak pogodzić język idiomu C++ rozdzielania nagłówka/źródła z szablonami?

W języku C i C++ bardzo powszechne jest umieszczanie deklaracji w plikach nagłówkowych i definicjach w plikach źródłowych i zachowanie dwóch całkowicie oddzielnych. Nie wydaje się to jednak możliwe (w żaden świetny sposób), jeśli chodzi o szablony i jak wszyscy wiemy, szablony są doskonałym narzędziem.

Ponadto Boost to głównie nagłówki, więc jest to poważny problem. Czy oddzielenie nagłówków od źródła nadal jest dobrym pomysłem w C++, czy nie powinienem polegać głównie na szablonach?

+5

To niedorzeczne, że to pytanie zostało zamknięte. Dla mnie jest jasne i oczywiste, o co mnie proszono. I myślę, że odpowiedź na to pytanie byłaby bardzo przydatna na tej stronie. – Omnifarious

+0

@Omni: Głosowałem, aby zamknąć to pytanie, ponieważ (IMHO) jest to kombinacja wojny płomieniowej, która czeka, aby się wydarzyć, i otwartych nieusankcjonowanych ("czy nie powinienem polegać głównie na szablonach?"). –

+0

@Ol Charlseworth - Ahh, tak, widzę, że używany język byłby trochę zapalny. Zamienię to na bardziej neutralne pytanie. – Omnifarious

Odpowiedz

18

instancji szablonu jest kosztowne w czasie kompilacji, ale virtualy darmo przy starcie . Zasadniczo za każdym razem, gdy używasz nowego typu szablonu, kompilator musi wygenerować kod dla tego nowego typu, dlatego kod znajduje się w nagłówku, aby kompilator miał później dostęp do kodu.

Umieszczenie całego kodu w pliku .cpp pozwala kompilatorowi skompilować ten kod tylko raz, co znacznie przyspiesza kompilację. Można teoretycznie napisać cały kod w nagłówkach, będzie działał dobrze, ale będzie to trwało wiecznie, aby skompilować bardzo duże projekty. Ponadto, gdy tylko zmienisz jedną linię w dowolnym miejscu, będziesz musiał odbudować wszystko.

Teraz możesz zapytać, dlaczego STL i BOOST nie są takie powolne? Właśnie tam przychodzą na ratunek skompilowane nagłówki. PCH pozwolił kompilatorowi wykonać najbardziej kosztowną pracę tylko raz. Działa to dobrze z kodem, który nie zmieni się często jak biblioteki, ale jego efekt jest całkowicie unieważniony dla kodu, który bardzo się zmienia, ponieważ będziesz musiał przekompilować cały zestaw prekompilowanych nagłówków za każdym razem. Kompilator używa również kilku sztuczek, aby uniknąć rekompilacji całego kodu szablonu w każdej jednostce kompilacji.

Należy również zauważyć, że C++ 0x wprowadzi jawne mechanizmy, które lepiej kontrolują tworzenie szablonu. Będziesz mógł jawnie tworzyć instancje szablonów i, co najważniejsze, zapobiegać instancji w niektórych jednostkach kompilacji. Jednak większość tej pracy jest już wykonywana przez większość kompilatorów bez naszej wiedzy.

Zasada jest więc taka, że ​​w swoim pliku .cpp umieść jak najwięcej kodu (i dołącz do niego dyrektywy). Jeśli nie możesz, cóż, nie możesz.

Moja rada byłaby: nie szablon tylko do cholery. Jeśli musisz szablonować, zachowaj ostrożność i pamiętaj, że wybierasz szybkość kompilacji i użyteczność szablonu.

+0

Ogromny +1 dla ciebie, proszę pana. – tenfour

+1

+1 za powiedzenie: nie szablon tylko dla do cholery –

+0

W C++ 03 istnieje również słowo kluczowe "export", ale jest zaimplementowane tylko w Comeau. –

7

Moim ulubionym jest to struktura:

plik nagłówka:

#ifndef HEADER_FILE 
#define HEADER_FILE 

template < typename T > 
class X { void method(); }; 

#include "header_impl.h" 

#endif 

plik Realizacja:

#ifndef HEADER_IMPL_FILE 
#define HEADER_IMPL_FILE 

#include "header.h" 

template < typename T > 
void X<T>::method() { } 

#endif 
+3

-1 chociaż może to być, z jakiegoś powodu, twoje ulubione, informacja ta nie jest zbyt użyteczna, nie mówiąc, jakie są jej zalety, i jak radzi sobie z przypadkami, w których T nie jest znane, dopóki szablon nie zostanie użyty. (jeśli strażnicy na implonie sugerują, że dodajesz gdzieś impl, chociaż tego nie mówisz, a posiadanie dwóch dołączonych plików byłoby prawie takie samo jak posiadanie większego pliku nagłówkowego) –

+0

@Pete Uh? T nigdy nie jest znana, dopóki szablon nie zostanie użyty, to jeden z głównych punktów szablonów. Oczywiście możesz używać szablonów nawet dla nieparametrycznego kodu, ale to pokonuje cel. Zapomniałem jednej linii w kodzie (to prawie wyłącznie dla narzędzi kodujących), powód dla strażników powinien być teraz jasny. –

+0

+1, to jest to, co zwykle robię, ale bez włączania "header.h" ponownie w "_impl.h". Może przydatne dla IntelliSense, ale niekonieczne. – Xeo

2

Myślę, że naprawdę ważną rzeczą do zrozumienia szablonów jest to, że parafrazując Bjarne Stroustrop, C++ jest naprawdę jak wiele języków w jednym. Konwencje i idiomy szablonów są inne niż w przypadku pisania "zwykłego" C++, prawie jak w innym języku.

To jest absolutnie dobry pomysł, aby odseparować pliki nagłówkowe od plików implementacyjnych w "zwykłym" C++, ponieważ pliki nagłówkowe informują kompilator o tym, co dostarczymy jako implementację jakiś czas później (w czasie połączenia). Jest to ważne, ponieważ ta separacja jest bardzo realna w większości popularnych systemów operacyjnych: czas połączenia może się zdarzyć, gdy użytkownik uruchomi program.Możesz skompilować implementację do plików binarnych (tak, dll) i wysyłać niezmienione nagłówki dla programistów, aby wiedzieć, jak użyć swojej nieprzejrzystej implementacji.

Teraz, dla szablonów, nie można tego zrobić, ponieważ kompilator musi w pełni rozwiązać wszystko pod w czasie kompilacji. Oznacza to, że podczas kompilowania nagłówków, muszą one mieć implementację szablonu, aby kompilator mógł rozpoznać nagłówki. Kompilator zasadniczo "un-szablony" szablony podczas kompilacji, więc nie ma opcji oddzielania interfejsu i realizacji szablonu C++.

Rozdzielenie interfejsu i implementacji to dobra praktyka, ogólnie rzecz biorąc, ale kiedy wędrujesz do szablonu-ziemi, wyraźnie wybierasz się w miejsce, w którym to po prostu nie jest możliwe - ponieważ to właśnie oznacza szablon: rozwiązać i zbudować implementację tego interfejsu w czasie kompilacji, a nie w środowisku wykonawczym.

-1

Rozdzielenie nagłówka i źródła nie jest idiomem C++, jest to raczej idiom języka C, dokładnie , ponieważ C++ preferuje użycie szablonów i funkcji wbudowanych, w miarę możliwości w celu zmniejszenia czasu wykonywania programu.

+0

Możesz użyć do tego całego optymalizatora programu. Jeśli umieścisz zbyt wiele rzeczy w plikach nagłówkowych, spowolni to kompilację, szczególnie w nietrywialnych projektach. –

1

Oto kilka technik używać podczas pisania kodu na matrycy, które poruszają implementacje do plików cpp:

  1. części poruszają się z metodami, które nie zależą od parametrów szablon w oddzielnych, bez szablonu funkcji pomocniczych lub klasy bazowe. Ciała mogą następnie przejść do własnych plików cpp.

  2. Pisanie deklaracji wspólnych specjalizacji. Definicje mogą żyć w ich własnych plikach cpp.