Jezyk C Metaprogramowanie za pomoca szablonow cppmet


IDZ DO
IDZ DO
PRZYKŁADOWY ROZDZIAŁ
PRZYKŁADOWY ROZDZIAŁ
Język C++.
SPIS TRE CI
SPIS TRE CI
Metaprogramowanie
KATALOG KSIĄŻEK
KATALOG KSIĄŻEK
za pomocą szablonów
KATALOG ONLINE
KATALOG ONLINE
Autorzy: David Abrahams, Aleksey Gurtovoy
Tłumaczenie: Rafał Jońca
ZAMÓW DRUKOWANY KATALOG
ZAMÓW DRUKOWANY KATALOG
ISBN: 83-7361-935-6
Tytuł oryginału: C++ Template Metaprogramming:
Concepts, Tools, and Techniques from Boost and Beyond
TWÓJ KOSZYK
TWÓJ KOSZYK
Format: B5, stron: 336
DODAJ DO KOSZYKA
DODAJ DO KOSZYKA
Metaprogramowanie to jedna z nowo ci, które pojawiły się ostatnio w wiecie języka
C++. Metaprogram to program będący w stanie modyfikować lub generować kod
CENNIK I INFORMACJE
CENNIK I INFORMACJE
innego programu. Wykorzystanie zasad metaprogramowania pozwala na przykład
na dynamiczną modyfikację programu podczas jego kompilacji. Pierwszym językiem
ZAMÓW INFORMACJE
ZAMÓW INFORMACJE
pozwalającym na korzystanie z możliwo ci metaprogramowania jest C++ biblioteką STL.
O NOWO CIACH
O NOWO CIACH
 C++. Metaprogramowanie za pomocą szablonów to książka przeznaczona dla tych
programistów, którzy korzystają już z biblioteki STL i chcą zastosować ją do tworzenia
ZAMÓW CENNIK
ZAMÓW CENNIK
metaprogramów. Opisano w niej zasady metaprogramowania, typy możliwe do
wykorzystania w szablonach przeznaczonych do implementacji funkcji związanych
z metaprogramowaniem oraz sposoby tworzenia szablonów modyfikujących programy
CZYTELNIA
CZYTELNIA
podczas kompilacji.
" Typy i metafunkcje
FRAGMENTY KSIĄŻEK ONLINE
FRAGMENTY KSIĄŻEK ONLINE
" Operacje, sekwencje i iteratory
" Algorytmy biblioteki MPL i tworzenie własnych algorytmów
" Usuwanie błędów w szablonach
" Modyfikowanie programu w czasie kompilacji
" Język DSEL
Metaprogramowanie to nowo ć. Poznaj je już teraz, aby być przygotowanym na dzień,
w którym stanie się standardem.
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Spis treści
Przedmowa .......................................................................................7
Podziękowania ..................................................................................9
Struktura książki ............................................................................11
Rozdział 1. Wprowadzenie ................................................................................13
1.1. Zaczynamy ............................................................................................................. 13
1.2. Czym jest metaprogram? ....................................................................................... 14
1.3. Metaprogramowanie w języku macierzystym ........................................................ 15
1.4. Metaprogramowanie w języku C++ ....................................................................... 15
1.5. Dlaczego metaprogramowanie? ............................................................................. 18
1.6. Kiedy stosować metaprogramowanie? ................................................................... 20
1.7. Dlaczego biblioteka metaprogramowania? ............................................................ 20
Rozdział 2. Cechy typu i manipulowanie nim ......................................................23
2.1. Powiązanie typów .................................................................................................. 23
2.2. Metafunkcje ........................................................................................................... 26
2.3. Metafunkcje numeryczne ....................................................................................... 29
2.4. Dokonywanie wyborów na etapie kompilacji ........................................................ 30
2.5. Krótka podróż po bibliotece Boost Type Traits ..................................................... 34
2.6. Metafunkcje bezargumentowe ............................................................................... 39
2.7. Definicja metafunkcji ............................................................................................ 40
2.8. Historia .................................................................................................................. 40
2.9. Szczegóły ............................................................................................................... 41
2.10. Ćwiczenia .............................................................................................................. 44
Rozdział 3. Dokładniejsze omówienie metafunkcji ..............................................47
3.1. Analiza wymiarowa ............................................................................................... 47
3.2. Metafunkcje wyższych rzędów .............................................................................. 56
3.3. Obsługa symboli zastępczych ................................................................................ 58
3.4. Więcej możliwości lambdy .................................................................................... 60
3.5. Szczegóły implementacji lambda ........................................................................... 61
3.6. Szczegóły ............................................................................................................... 64
3.7. Ćwiczenia .............................................................................................................. 66
Rozdział 4. Operacje i otoczki typów całkowitych ..............................................69
4.1. Operacje i otoczki typu logicznego ........................................................................ 69
4.2. Operacje i otoczki liczb całkowitych ..................................................................... 76
4.3. Ćwiczenia .............................................................................................................. 80
4 Spis treści
Rozdział 5. Sekwencje i iteratory ......................................................................83
5.1. Pojęcia ................................................................................................................... 83
5.2. Sekwencje i algorytmy ........................................................................................... 84
5.3. Iteratory ................................................................................................................. 85
5.4. Pojęcia związane z iteratorem ................................................................................ 85
5.5. Pojęcia sekwencji ................................................................................................... 89
5.6. Równość sekwencji ............................................................................................... 94
5.7. Wewnętrzne operacje sekwencji ............................................................................ 94
5.8. Klasy sekwencji ..................................................................................................... 95
5.9. Otoczki sekwencji liczb całkowitych ..................................................................... 99
5.10. Wyprowadzanie sekwencji .................................................................................. 100
5.11. Pisanie własnych sekwencji ................................................................................. 101
5.12. Szczegóły ............................................................................................................ 110
5.13. Ćwiczenia ............................................................................................................ 111
Rozdział 6. Algorytmy .....................................................................................115
6.1. Algorytmy, idiomy, wielokrotne użycie i abstrakcja ........................................... 115
6.2. Algorytmy biblioteki MPL .................................................................................. 117
6.3. Insertery ............................................................................................................... 118
6.4. Podstawowe algorytmy sekwencji ....................................................................... 121
6.5. Algorytmy zapytań .............................................................................................. 123
6.6. Algorytmy budowania sekwencji ......................................................................... 123
6.7. Pisanie własnych algorytmów .............................................................................. 126
6.8. Szczegóły ............................................................................................................. 127
6.9. Ćwiczenia ............................................................................................................ 128
Rozdział 7. Widoki i adaptery iteratorów .........................................................131
7.1. Kilka przykładów ................................................................................................. 131
7.2. Pojęcie widoku .................................................................................................... 137
7.3. Adaptery iteratora ................................................................................................ 137
7.4. Tworzenie własnego widoku ............................................................................... 138
7.5. Historia ................................................................................................................ 140
7.6. Ćwiczenia ............................................................................................................ 140
Rozdział 8. Diagnostyka .................................................................................143
8.1. Powieść o poprawianiu błędów ........................................................................... 143
8.2. Korzystanie z narzędzi do analizy wyników diagnostyki .................................... 152
8.3. Zamierzone generowanie komunikatów diagnostycznych ................................... 156
8.4. Historia ................................................................................................................ 167
8.5. Szczegóły ............................................................................................................. 167
8.6. Ćwiczenia ............................................................................................................ 168
Rozdział 9. Przekraczanie granicy między czasem kompilacji
i wykonywania programu ...............................................................171
9.1. Algorytm for_each ............................................................................................... 171
9.2. Wybór implementacji .......................................................................................... 174
9.3. Generatory obiektów ............................................................................................ 178
9.4. Wybór struktury ................................................................................................... 180
9.5. Złożenie klas ........................................................................................................ 184
9.6. Wskazniki na funkcje (składowe) jako argumenty szablonów ............................ 187
9.7. Wymazywanie typu ............................................................................................. 189
9.8. Wzorzec zadziwiająco powracającego szablonu .................................................. 195
9.9. Jawne zarządzanie zbiorem przeciążeń ................................................................ 200
9.10. Sztuczka z sizeof ................................................................................................. 202
9.11. Podsumowanie ..................................................................................................... 203
9.12. Ćwiczenia ............................................................................................................ 203
Spis treści 5
Rozdział 10. Język osadzony zależny od dziedziny ..............................................205
10.1. Mały język& ....................................................................................................... 205
10.2. & przechodzi długą drogę .................................................................................... 208
10.3. Języki DSL  podejście odwrotne ..................................................................... 215
10.4. C++ jako język gospodarza ................................................................................. 218
10.5. Blitz++ i szablony wyrażeń ................................................................................. 220
10.6. Języki DSL ogólnego stosowania ...................................................................... 225
10.7. Biblioteka Boost Spirit ........................................................................................ 234
10.8. Podsumowanie ..................................................................................................... 240
10.9. Ćwiczenia ............................................................................................................ 241
Rozdział 11. Przykład projektowania języka DSEL ..............................................243
11.1. Automaty skończone ........................................................................................... 243
11.2. Cele projektu szkieletu ........................................................................................ 246
11.3. Podstawy interfejsu szkieletu .............................................................................. 247
11.4. Wybór języka DSL .............................................................................................. 248
11.5. Implementacja ..................................................................................................... 254
11.6. Analiza ................................................................................................................ 259
11.7. Kierunek rozwoju języka ..................................................................................... 261
11.8. Ćwiczenia ............................................................................................................ 261
Dodatek A Wprowadzenie do metaprogramowania za pomocą preprocesora .....265
A.1. Motywacja ........................................................................................................... 265
A.2. Podstawowe abstrakcje preprocesora ................................................................... 267
A.3. Struktura biblioteki preprocesora ......................................................................... 269
A.4. Abstrakcje biblioteki preprocesora ....................................................................... 269
A.5. Ćwiczenie ............................................................................................................. 286
Dodatek B Słowa kluczowe typename i template ............................................287
B.1. Zagadnienia .......................................................................................................... 288
B.2. Reguły .................................................................................................................. 291
Dodatek C Wydajność kompilacji ...................................................................299
C.1. Model obliczeniowy ............................................................................................. 299
C.2. Zarządzanie czasem kompilacji ............................................................................ 302
C.3. Testy ..................................................................................................................... 302
Dodatek D Podsumowanie przenośności biblioteki MPL .................................315
Bibliografia ...................................................................................317
Skorowidz .....................................................................................321
Rozdział 1.
Wprowadzenie
Warto potraktować ten rozdział jako rozgrzewkę przed pozostałą częścią książki.
Przećwiczymy tutaj najważniejsze narzędzia, a także zapoznamy się z podstawowymi
pojęciami i terminologią. Pod koniec rozdziału każdy powinien już mniej więcej wie-
dzieć, o czym jest niniejsza książka, i być głodnym kolejnych informacji.
1.1. Zaczynamy
Jedną z przyjemnych kwestii związanych z metaprogramowaniem szablonami jest
współdzielenie pewnej właściwości z tradycyjnymi, starymi systemami. Po napisaniu
metaprogramu można go używać bez zastanawiania się nad jego szczegółami 
oczywiście o ile wszystko działa prawidłowo.
Aby uświadomić każdemu, że przedstawiona kwestia to nie tylko wymyślna teoria,
prezentujemy prosty program C++, który po prostu używa elementu zaimplementowa-
nego jako metaprogram szablonu.







Nawet jeśli jest się dobrym w arytmetyce binarnej i od razu można odgadnąć wynik
działania programu bez jego uruchamiania, warto zadać sobie ten trud i go skompilo-
wać oraz uruchomić. Poza upewnieniem się w kwestii samej koncepcji, jest to dobry
test sprawdzający, czy wykorzystywany kompilator potrafi obsłużyć kod przedsta-
wiany w książce. Wynikiem działania programu powinno być wyświetlenie na stan-
dardowym wyjściu wartości dziesiętnej liczby binarnej 101010:

14 Rozdział 1. f& Wprowadzenie
1.2. Czym jest metaprogram?
Gdy potraktować słowo metaprogram dosłownie, oznacza ono  program o programie 1.
Od strony bardziej praktycznej metaprogram to program modyfikujący kod. Choć sama
koncepcja brzmi nieco dziwacznie, zapewne nieraz nieświadomie korzystamy z takich
rozwiązań. Przykładem może być kompilator C++, który modyfikuje kod C++ w taki
sposób, by uzyskać kod w asemblerze lub kod maszynowy.
Generatory analizatorów składniowych takie jak YACC [Joh79] to kolejny przykład
programów manipulujących programem. Wejściem dla YACC jest wysokopoziomowy
opis analizatora składniowego zawierający zasady gramatyczne i odpowiednie pole-
cenia umieszczone w nawiasach klamrowych. Aby na przykład przetworzyć i wyko-
nać działania arytmetyczne zgodnie z przyjętą kolejnością wykonywania działań,
można zastosować następujący opis gramatyki dla programu YACC.













Program YACC wygeneruje plik zródłowy języka C++ zawierający (poza wieloma
innymi elementami) funkcję , którą wywołuje się w celu przeanalizowania
tekstu zgodnie z podaną gramatyką i wykonania określonych działań2.





Użytkownicy programu YACC działają przede wszystkim w dziedzinie projektowa-
nia analizatorów składniowych, więc język YACC można nazwać językiem specjali-
stycznym (dziedzinowym). Ponieważ pozostała część głównego programu wymaga
zastosowania ogólnego języka programowania i musi się komunikować z analizato-
rem składniowym, YACC konwertuje język specjalistyczny na język macierzysty, C,
który użytkownik kompiluje i konsoliduje z pozostałym kodem. Język specjalistyczny
przechodzi więc przez dwa kroki przekształceń, a użytkownik bardzo dobrze zna gra-
nicę między nim a pozostałą częścią programu głównego.
1
W filozofii, podobnie jak w programowaniu, przedrostek  meta oznacza  o lub  o jeden poziom
opisowy wyżej . Wynika to z oryginalnego greckiego znaczenia  ponad lub  poza .
2
Oczywiście trzeba jeszcze zaimplementować odpowiednią funkcję dokonującą rozbioru tekstu.
W rozdziale 10. znajduje się pełny przykład. Ewentualnie warto zajrzeć do dokumentacji programu YACC.
1.4. Metaprogramowanie w język C++ 15
1.3. Metaprogramowanie
w języku macierzystym
YACC to przykład translatora  metaprogramu, którego język specjalistyczny różni
się od języka macierzystego. Bardziej interesująca postać metaprogramowania jest
dostępna w językach takich jak Scheme [SS75]. Programista metaprogramu Scheme
definiuje własny język specjalistyczny jako podzbiór dopuszczalnych programów sa-
mego języka Scheme. Metaprogram wykonuje się w tym samym kroku przekształceń
co pozostała część programu użytkownika. Programiści często przemieszczają się
między typowym programowaniem, metaprogramowaniem i pisaniem języków spe-
cjalistycznych, nawet tego nie dostrzegając. Co więcej, potrafią w sposób niemalże
nierozróżnialny scalić w tym samym systemie wiele dziedzin.
Co ciekawe, kompilator C++ zapewnia niemalże dokładnie taką samą użyteczność
metaprogramowania jak przedstawiony wcześniej przykład. Pozostała część książki
omawia odblokowywanie siły tkwiącej w szablonach i opisuje sposoby jej użycia.
1.4. Metaprogramowanie w języku C++
W języku C++ metaprogramowanie odkryto niemalże przypadkowo ([Unruh94],
[Veld95b]), gdy udowodniono, iż szablony zapewniają bardzo elastyczny język
metaprogramowania. W niniejszym podrozdziale omówimy podstawowe mechanizmy
i typowe rozwiązania używane w metaprogramowaniu w języku C++.
1.4.1. Obliczenia numeryczne
Najprostsze metaprogramy C++ wykonują obliczenia na liczbach całkowitych w trakcie
kompilacji. Jeden z pierwszych metaprogramów został przedstawiony na spotkaniu
komitetu C++ przez Erwina Unruha  w zasadzie był to niedozwolony fragment ko-
du, którego komunikat o błędzie zawierał ciąg wyliczonych liczb pierwszych!
Ponieważ niedozwolonego kodu nie da się wydajnie stosować w dużych systemach,
przyjrzyjmy się bardziej praktycznym aplikacjom. Kolejny metaprogram (który leży
u podstaw przedstawionego wcześniej testu kompilatora) zamienia liczby dziesiętne bez
znaku na ich odpowiedniki binarne, co umożliwia wyrażanie stałych binarnych w przy-
jaznej formie.




dodaje bardziej znaczący bit
przejście do mniej znaczącego bitu

16 Rozdział 1. f& Wprowadzenie
specjalizacja
przerywa rekurencję








Jeżeli ktoś zastanawia się, gdzie jest program, proponujemy rozważyć, co się stanie
w momencie próby dostępu do zagnieżdżonej składowej z . Two-
rzy się egzemplarze szablonu z coraz to mniejszymi aż do osiągnięcia przez
zera. Warunkiem końca jest specjalizacja. Innymi słowy, przypomina to działanie
funkcji rekurencyjnej. Czy jest to program czy może funkcja? Ogólnie rzecz biorąc,
kompilator zinterpretuje ten krótki metaprogram.
Sprawdzanie błędów
Nic nie stoi na przeszkodzie, aby użytkownik przekazał do wartość 678,
która nie jest poprawną wartością binarną. Wynik na pewno nie będzie sensowny
(zostanie wykonane działanie 6"22+7"21+8"20), a przekazanie wartości 678 na pewno
wskazuje błąd użytkownika. W rozdziale 3. przedstawimy rozwiązanie zapewniające, iż
skompiluje się tylko wtedy, gdy reprezentacja dziesiętna będzie
się składała tylko z samych zer i jedynek.
Ponieważ język C++ wprowadza rozróżnienie między wyrażeniami obliczanymi w trakcie
kompilacji i w trakcie działania programu, metaprogramy wyglądają inaczej niż ich
tradycyjne odpowiedniki. Podobnie jak w Scheme programista metaprogramów C++
pisze kod w tym samym języku co tradycyjne programy, ale w C++ ma dostęp tylko
do podzbioru elementów języka związanych z etapem kompilacji. Porównajmy po-
przedni program z prostą wersją wykonaną jako tradycyjny program.




Podstawowa różnica między przedstawionymi wersjami polega na sposobie obsługi
warunku zakończenia: metaprogram używa specjalizacji szablonu do opisu tego, co
dzieje się dla równego zero. Przerywanie za pomocą specjalizacji to element wspólny
niemal dla wszystkich metaprogamów C++, choć czasem wszystko ukryte jest za in-
terfejsem biblioteki metaprogramowania.
Inną bardzo ważną różnicę między językiem C++ tradycyjnym i wykonywanym w trakcie
kompilacji obrazuje poniższa wersja , która korzysta z pętli zamiast z rekurencji.




1.4. Metaprogramowanie w język C++ 17






Choć ta wersja jest dłuższa od rozwiązania rekurencyjnego, zapewne zastosuje ją
większość programistów C++, gdyż jest na ogół wydajniejsza od rekurencji.
Część języka C++ związana z czasem kompilacji nazywana jest często  językiem
czysto funkcyjnym , a to z powodu właściwości, jakie współdzieli z językami takimi
jak Haskell: (meta)dane są niezmienne, a (meta)funkcje nie mogą mieć efektów
ubocznych. Wynika z tego, iż C++ czasu kompilacji nie posiada tradycyjnych zmien-
nych używanych w typowym języku C++. Ponieważ nie można napisać pętli (poza
pętlą nieskończoną) bez sprawdzania pewnego zmiennego stanu zakończenia, iteracje
po prostu nie są dostępne w trakcie kompilacji. Z tego względu w metaprogramach
C++ wszechobecna jest rekurencja.
1.4.2. Obliczenia typu
Dużo ważniejsza od obliczania wartości liczbowych w trakcie kompilacji jest zdol-
ność języka C++ do obliczania typów. W zasadzie w pozostałej części książki domi-
nuje obliczanie typu  pierwszy przykład przedstawiamy już na początku kolejnego
rozdziału. Choć jesteśmy tutaj bardzo bezpośredni, zapewne większość osób traktuje
metaprogramowanie szablonami jako  obliczenia związane z typami .
Choć dla dobrego zrozumienia obliczeń typów warto przeczytać rozdział 2., już teraz
zamierzamy przedstawić przedsmak ich siły. Pamiętasz kalkulator wyrażeń wykonany
w YACC? Wychodzi na to, iż nie potrzebujemy translatora, aby osiągnąć podobne działa-
nie. Po odpowiednim otoczeniu kodu przez bibliotekę Boost Spirit poniższy w pełni
poprawny kod C++ działa w zasadzie identycznie.














Każde przypisanie zapamiętuje obiekt funkcji, który analizuje i oblicza element grama-
tyki podany po prawej stronie. Zachowanie każdego zapamiętanego obiektu funkcyjnego
18 Rozdział 1. f& Wprowadzenie
w momencie wywołania jest w pełni określone jedynie przez typ wyrażenia użytego
do jego wykonania. Typ każdego wyrażenia jest obliczany przez metaprogram
związany z poszczególnymi operatorami.
Podobnie jak YACC biblioteka Spirit jest metaprogramem generującym analizatory
składniowe dla podanej gramatyki. Jednak w odróżnieniu od YACC Spirit definiuje
swój język specjalistyczny jako podzbiór samego języka C++. Jeśli jeszcze nie do-
strzegasz tego powiązania, nic nie szkodzi. Po przeczytaniu niniejszej książki na
pewno wszystko stanie się oczywiste.
1.5. Dlaczego metaprogramowanie?
Jakie są zalety metaprogramowania? Z pewnością istnieją prostsze sposoby rozwiąza-
nia przedstawionych tutaj problemów. Przyjrzyjmy się dwóm innym podejściom i prze-
analizujmy ich zastosowanie pod kątem interpretacji wartości binarnych i konstrukcji
analizatorów składniowych.
1.5.1. Pierwsza alternatywa
 obliczenia w trakcie działania programu
Chyba najprostsze podejście związane jest z wykonywaniem obliczeń w trakcie działania
programu zamiast na etapie kompilacji. Można w tym celu wykorzystać jedną z imple-
mentacji funkcji z poprzedniej części rozdziału. System analizy składniowej
mógłby dokonywać interpretacji gramatyki w trakcie działania programu, na przykład
przy pierwszym zadaniu analizy składniowej.
Oczywistym powodem wykorzystania metaprogramowania jest możliwość wykonania
jak największej liczby zadań jeszcze przed uruchomieniem programu wynikowego 
w ten sposób uzyskuje się szybsze programy. W trakcie kompilacji gramatyki YACC
dokonuje analizy i optymalizacji tabeli generacji, co w przypadku wykonywania tych
zadań w trakcie działania programu zmniejszyłoby ogólną wydajność. Podobnie, po-
nieważ wykonuje swoje zadanie w trakcie kompilacji, jest dostępna
jako stała w trakcie kompilacji, a tym samym kompilator może ją bezpośrednio za-
mienić na kod obiektu, zaoszczędzając wyszukania w pamięci, gdy zostanie użyta.
Bardziej subtelny, ale i ważniejszy argument przemawiający za metaprogramowaniem
wynika z faktu, iż wynik obliczeń może wejść w znacznie głębszą interakcję z doce-
lowym językiem. Na przykład rozmiar tablicy można poprawnie określić na etapie
kompilacji tylko jako stałą, na przykład  nie można tego zrobić
za pomocą wartości zwracanej przez funkcję. Akcje zawarte w nawiasach klamro-
wych gramatyki YACC mogą zawierać dowolny kod C lub C++, który zostanie wy-
konany jako część analizatora składniowego. Takie rozwiązanie jest możliwe tylko
dlatego, że akcje są przetwarzane w trakcie kompilacji gramatyki i są przekazywane
do docelowego kompilatora C++.
1.5. Dlaczego metaprogramowanie? 19
1.5.2. Druga alternatywa  analiza użytkownika
Zamiast wykonywać obliczenia w trakcie kompilacji lub działania programu, wykonuje-
my wszystko ręcznie. Przecież przekształcanie wartości binarnych na ich odpowiedniki
szesnastkowe jest powszechnie stosowaną praktyką. Podobnie ma się sprawa z krokami
przekształceń wykonywanymi przez program YACC lub bibliotekę Boost Spirit.
Jeśli alternatywą jest napisanie metaprogramu, który zostanie wykorzystany tylko raz,
można argumentować, iż analiza użytkownika jest wygodniejsza  łatwiej skonwertować
ręcznie wartość binarną na szesnastkową niż pisać wykonujący to samo zadanie me-
taprogram. Jeżeli jednak wystąpień takiej sytuacji będzie kilka, wygoda bardzo szybko
przesuwa się w stronę przeciwną. Co więcej, po napisaniu metaprogramu można go
rozpowszechnić, aby inni programiści również mogli wygodniej pisać programy.
Niezależnie od liczby użyć metaprogramu zapewnia on użytkownikowi większą siłę
wyrazu kodu, gdyż można określić wynik w formie najlepiej tłumaczącej jego działa-
nie. W kontekście, gdzie wartości poszczególnych bitów mają duże znaczenie, znacz-
nie większy sens ma napisanie niż lub tradycyjne .
Podobnie kod w języku C dla ręcznie napisanego analizatora kodu na ogół zasłania
logiczne związki między poszczególnymi elementami gramatyki.
Ponieważ ludzie są ułomni, a logikę metaprogramu wystarczy napisać tylko raz, wy-
nikowy program ma większą szansę być poprawnym i łatwiej modyfikowalnym.
Ręczna zamiana wartości binarnych zwiększa prawdopodobieństwo popełnienia błę-
du, bo jest bardzo nudna. Dla odróżnienia ręczne tworzenie tabel analizy składniowej
jest tak niewdzięcznym zadaniem, iż unikanie w tej kwestii błędów jest poważnym
argumentem za korzystaniem z generatorów takich jak YACC.
1.5.3. Dlaczego metaprogramowanie w C++?
W języku takim jak C++, gdzie język specjalistyczny stanowi po prostu podzbiór języka
używanego w pozostałej części programu, metaprogramowanie jest szczególnie wy-
godne i użyteczne.
Użytkownik może od razu korzystać z języka specjalistycznego bez uczenia
się nowej składni lub przerywania układu pozostałej części programu.
Powiązanie metaprogramów z pozostałym kodem, w szczególności innymi
metaprogramami, staje się bardziej płynne.
Nie jest wymagany żaden dodatkowy krok w trakcie kompilacji (jak ma
to miejsce w przypadku YACC).
W tradycyjnym programowaniu powszechne są starania o odnalezienie złotego środka
między wyrazistością, poprawnością a wydajnością kodu. Metaprogramowanie ułatwia
przerwanie tej klasycznej szarady i przeniesienie obliczeń wymaganych do uzyskania
wyrazistości i poprawności do etapu kompilacji.
20 Rozdział 1. f& Wprowadzenie
1.6. Kiedy stosować
metaprogramowanie?
Przedstawiliśmy kilka odpowiedzi na pytanie dlaczego metaprogramowanie i kilka
przykładów wyjaśniających, jak działa metaprogramowanie. Warto jeszcze wyjaśnić,
kiedy warto je stosować. W zasadzie już przedstawiliśmy większość najważniejszych
kryteriów stosowania metaprogramowania szablonami. Jeśli spełnione są dowolne
trzy z poniższych warunków, warto zastanowić się nad rozwiązaniem wykorzystującym
metaprogramowanie.
Chcesz, aby kod został wyrażony w kategoriach dziedziny problemowej.
Na przykład chcesz, by analizator składni przypominał gramatykę formalną,
a nie zbiór tabel i podprocedur, lub działania na tablicach przypominały
notację znaną z obiektów macierzy lub wektorów, zamiast stanowić
zbiór pętli.
Chcesz uniknąć pisania dużej ilości podobnego kodu implementacyjnego.
Musisz wybrać implementację komponentu na podstawie właściwości
jego parametrów typu.
Chcesz skorzystać z zalet programowania generycznego w C++, na przykład
statycznego sprawdzania typów i dostosowywania zachowań bez utraty
wydajności.
Chcesz to wszystko wykonać w języku C++ bez uciekania się
do zewnętrznych narzędzi i generatorów kodu zródłowego.
1.7. Dlaczego biblioteka
metaprogramowania?
Zamiast zajmować się metaprogramowaniem od podstaw, będziemy korzystali z wyso-
kopoziomowej pomocy biblioteki MPL (Boost Metaprogramming Library). Nawet je-
śli ktoś nie wybrał tej książki w celu zapoznania się ze szczegółami MPL, sądzimy, że
czas poświęcony na jej naukę nie pójdzie na marne, gdyż łatwo ją wykorzystać w co-
dziennej pracy.
1. Jakość. Większość programistów używających komponentów
metaprogramowania szablonami traktuje je  całkiem słusznie  jako
szczegóły implementacyjne wprowadzane w celu ułatwienia większych
zadań. Dla odróżnienia, autorzy MPL skupili się na wykonaniu użytecznych
narzędzi wysokiej jakości. Ogólnie komponenty z biblioteki są bardziej
elastyczne i lepiej zaimplementowane niż te, które wykonałoby się samemu
w celu przeprowadzenia innych zadań. Co więcej, przyszłe wydania
z pewnością będą ulepszane i optymalizowane.
1.7. Dlaczego biblioteka metaprogramowania? 21
2. Ponowne użycie. Wszystkie biblioteki hermetyzują kod jako komponent
wielokrotnego użytku. Co więcej, dobrze zaprojektowana biblioteka ogólna
zapewnia szkielet pojęciowy mentalnego modelu rozwiązywania pewnych
problemów. Podobnie jak standardowa biblioteka języka C++ dostarcza
iteratory i protokół obiektów funkcyjnych, biblioteka MPL zapewnia iteratory
typów i protokół metafunkcyjny. Dobrze wykonany szkielet pozwala
programiście skupić się na decyzjach projektowych i szybkim wykonaniu
właściwego zadania.
3. Przenośność. Dobra biblioteka potrafi gładko przejść przez niuanse różnic
w platformach sprzętowych. Choć w teorii żaden z metaprogramów języka
C++ nie powinien mieć problemów z przenośnością, rzeczywistość jest inna
nawet po 6 latach od standaryzacji. Nie powinno to jednak dziwić  szablony
C++ to najbardziej złożony aspekt tego języka programowania, który
jednocześnie stanowi o sile metaprogramowania C++.
4. Zabawa. Wielokrotne pisanie tego samego kodu jest wyjątkowo nudne.
Szybkie połączenie komponentów wysokiego poziomu w czytelne, eleganckie
rozwiązanie to czysta zabawa! Biblioteka MPL redukuje nudę, eliminując
potrzebę powtarzania najbardziej typowych wzorców metaprogramowania.
Przede wszystkim elegancko unika się specjalizacji przerywających i jawnych
rekurencji.
5. Wydajność wytwarzania. Poza satysfakcją personelu zdrowie projektów
zależy również od przyjemności czerpanej z programowania. Gdy programista
przestaje mieć frajdę z programowania, staje się zmęczony i powolny  błędny
kod jest bardziej kosztowny od kodu pisanego dobrze, ale powoli.
Jak łatwo się przekonać, biblioteka MPL jest pisana zgodnie z tymi samymi zasadami,
które przyświecają tworzeniu innych bibliotek. Wydaje nam się, że jej pojawienie się
jest zwiastunem, iż metaprogramowanie szablonami jest gotowe opuścić pracownie
badawcze i zacząć być stosowane przez programistów w codziennej pracy.
Chcielibyśmy zwrócić szczególną uwagę na czwarty z przedstawionych punktów. Bi-
blioteka MPL nie tylko ułatwia korzystanie z metaprogramowania, ale również czyni
je czystą przyjemnością. Mamy nadzieję, że innym osobom uczenie się jej przyniesie
tyle radości, co nam przyniosło jej tworzenie i wykorzystywanie.


Wyszukiwarka

Podobne podstrony:
Wykonywanie przedmiotów za pomocą obróbki ręcznej skrawaniem(1)
Dane biometryczne – klucz do włamania i przeprogramowania osoby za pomocą czarnej magii
Projekt wyznacenie przyśpieszenia ziemskiego za pomocą układu wahadla matematycznego
Oszacowanie parametrów charakterystyk podatnych połączeń stalowych za pomocą sieci neuro rozmytej
2 Wyznaczanie gęstości ciała stałego i cieczy za pomocą piknometru
konwersja za pomocą progr Super 2008
Diagnoza za pomoca kodow blyskowych
Sterownik urządzeń elektrycznych za pomocą portu LPT
24 Wyznaczanie długości?li światła za pomocą siatki dyfrakcyjnej i spektrometru
Optymalizacja niezawodnościowa płaskich układów kratowych za pomocą zbiorów rozmytych
Proste rachunki wykonywane za pomocą komputera

więcej podobnych podstron