Czy szablony C ++ są rodzajem uwielbianych makr?

27

Z różnych porównań szablonów C ++ i generycznych C # / Java takich jak ten -

/programming/31693/what-are-the-differences-between-generics-in-c-and-java-and-templates-in-c/31929#31929

Mam wrażenie, że szablony C ++ są implementowane przez pewnego rodzaju przetwarzanie wstępne (zamiana zwykłego tekstu przed parsowaniem), a nie kompilowanie. Ponieważ sprawdzanie typu w szablonach C ++ przypomina makra C. Mam na myśli, że jeśli są jakieś błędy, są to błędy wygenerowanego kodu po przetworzeniu bloków szablonów, a nie samych szablonów. Innymi słowy, są one tylko rodzajem wyższej wersji makr w C.

Potem znalazłem kilka innych faktów na poparcie tego-

  • Pomyślałem, że jeśli szablony C ++ są implementowane przez przetwarzanie wstępne, pojawią się problemy z dynamicznym łączeniem (przy użyciu .dll). Wspierało to szybkie google.

  • Inną kwestią jest to, że stałe liczb całkowitych mogą być przekazywane jako argumenty do szablonów. I obsługuje nawet pewnego rodzaju rekurencję. Ale ta rekurencja nie występuje w skompilowanym kodzie zestawu / maszyny. Elementem rekurencyjnym zarządza się w czasie kompilacji, generując funkcje dla każdego wywołania rekurencyjnego, a tym samym posiadając większy, ale szybszy plik wykonywalny.

Chociaż w przeciwieństwie do makr C, ma pewne lepsze umiejętności. Ale czy szablon C ++ nie jest implementowany z jakimś rodzajem przetwarzania wstępnego? Jak to jest zaimplementowane w różnych kompilatorach C ++?

Gulszan
źródło
19
Nie. Szablony C ++ są kompilowane.
Edward Strange
2
Jaka jest twoja definicja „przetwarzania wstępnego”? A „kompilowania”? Odpowiednio szeroka definicja „przetwarzania wstępnego” może obejmować wszystko, co robi kompilator; w końcu kompilator tak naprawdę przetwarza źródło, zanim zostanie wykonane, nie?
James McNellis,
@James McNellis IMHO, jeśli możesz po prostu odróżnić przetwarzanie wstępne od wszystkich innych rzeczy wykonanych na potrzeby kompilacji, wystarczy zrozumieć moje pytanie. Dla wyjaśnienia preprocessor- en.wikipedia.org/wiki/Preprocessor#Lexical_preprocessors
Gulshan
6
Jeśli odwołujesz się do tej formy wstępnego przetwarzania, to nie, szablony C ++ absolutnie nie są jakimś uwielbionym makrem.
James McNellis,
1
Język szablonów jest właściwie ukończony, więc są czymś więcej niż ulepszonymi makrami.
davidk01

Odpowiedzi:

9

Szablony C ++ są rodzajem głupich makr Lisp (lub nawet więcej, Scheme). Jest to kompletny język Turinga, który ocenia się w czasie kompilacji, ale jest poważnie ograniczony, ponieważ nie ma dostępu z tego języka do bazowego środowiska C ++. Tak, tak, szablony C ++ można postrzegać jako formę przetwarzania wstępnego, z bardzo ograniczoną interakcją z generowanym kodem.

Logika SK
źródło
2
„ale jest poważnie ograniczony, ponieważ nie ma dostępu z tego języka do bazowego środowiska C ++.” -- Co to znaczy? Próbowałem przeanalizować to oświadczenie, ale nie powiodło się.
quant_dev,
2
Uhm, właściwie ... github.com/kmichel/bf0x
Anton Golov
3
@ SK-logic: Nawiasem mówiąc, C ++ 11 to C ++, chyba że (pedantycznie) traktujesz różne wersje tego samego języka jako różne języki.
Jon Purdy,
3
@Jon Purdy, C ++ 11 nie istniało (oficjalnie) do czasu tej odpowiedzi. W dzisiejszych czasach przykład byłby bardziej skomplikowany, na przykład rozkład struktury danych, użycie funkcji bibliotecznej itp.
SK-logic
1
@ SK-logic: Czy znasz implementację C ++ z makrami podobnymi do Lisp? Mam dość ograniczeń szablonów. Przykład języka składniowego w stylu C ++ z potężnym systemem makr w Haxe: haxe.org/manual/macros . (Nie pomaga mi to, ponieważ używam C ++ do jego celu - programowania 8-bitowych mikrokontrolerów; istnieją lepsze języki na cokolwiek innego).
pfalcon,
41

Prawdopodobnie największą różnicą jest to, że makra C są rozwijane w fazie wstępnego przetwarzania, zanim zostanie wykonana inna kompilacja, podczas gdy szablony C ++ są częścią kompilacji. Oznacza to, że szablony C ++ są między innymi świadome typu i mają zasięg, a nie są prostym zastępowaniem tekstu. Mogą kompilować się do rzeczywistych funkcji, dzięki czemu unikają większości problemów, które mają makra. Bycie świadomym typu oznacza, że ​​mogą być ogólne lub specjalistyczne: na przykład łatwo jest udostępnić funkcję swapszablonu, a także łatwo napisać specjalizacje, które działają dobrze, nawet jeśli obiekty zarządzają pamięcią sterty.

Dlatego: szablony C ++ nie przetwarzają wstępnie w tym samym sensie, co makra, nie są rodzajem makra C i nie można używać makr C do powielania tego, co robią szablony.

Szablony znajdują się w plikach nagłówków, a nie w bibliotekach połączonych, to prawda, ale jeśli dostarczasz plik dll, prawdopodobnie dostarczasz również plik nagłówkowy do użycia.

David Thornley
źródło
12
Nie muszą żyć w pliku nagłówkowym (to tylko najprostsza technika ich użycia). Możesz zdefiniować je w pliku źródłowym i ręcznie wymusić utworzenie szablonu w pliku źródłowym (jednostka kompilacji). Łączenie następnie odbierze instancje jak zwykle (jest to technika ograniczania szablonów do określonych typów i niedozwolania wszystkich typów ogólnych).
Martin York,
@Martin: Nie jestem pewien, czy ta technika (o ile jest obsługiwana) jest rzeczywiście wyraźnie obsługiwana przez standard. W przeciwnym razie wszystkie kompilatory zostałyby exportjuż zaimplementowane. Wiem, że to działa w przypadku funkcji, ale wątpię, aby działało w przypadku klas: skąd znasz ich rozmiar?
Matthieu M.
@Matthieu M: To nie ma nic wspólnego ze słowem kluczowym eksportu. Zajmuje się tworzeniem szablonów „Jawne” i jest dobrze zdefiniowany w standardzie.
Martin York,
2
@Matthieu M .: Jeśli kompilator zna sygnaturę funkcji, a linker może znaleźć implementację, wszystko jest fajne. Dotyczy to tego, czy funkcja jest funkcją szablonu, czy nie. W praktyce zazwyczaj znajdują się w plikach nagłówkowych, ponieważ wymuszanie określonych instancji jest zwykle więcej pracy niż warte, ale Martin ma rację, zwracając uwagę na alternatywę.
David Thornley,
Wiem, że to działa na pewno w przypadku wyspecjalizowanych funkcji. Jestem jednak całkiem pewien, że nie działa w przypadku klas, o co mi chodziło. Myślę, że to działa również dla metod z wyspecjalizowanych klas, ale nie wiem, czy jest to standard, czy nie.
Matthieu M.,
5

Czy to ważne, w jaki sposób są wdrażane? Wczesne kompilatory C ++ były tylko procesorami wstępnymi, które dostarczały kod do kompilatora ac, nie oznacza to, że C ++ jest tylko uwielbionym makrem.

Szablony eliminują potrzebę makr, zapewniając bezpieczniejszy, wydajniejszy i specjalizowany (nawet nie sądzę, że to prawdziwe słowo) sposób implementacji kodu dla wielu typów.

Istnieje wiele sposobów wykonywania kodu typu szablonowego w c, z których żaden nie jest zbyt przyjemny, gdy wyjdziesz poza proste typy.

Martin Beckett
źródło
Nie mówiłem o C ++ jako chwalebnym makrze. Bardzo podziwiam C ++. Po prostu ciekawy.
Gulshan
2
@Gulshan: Nie, nic o tym nie powiedziałeś. Niemniej jednak tak działały wczesne kompilatory C ++ (z wyjątkiem tego, że CFront był czymś w rodzaju kompilatora, a nie tylko preprocesora makr), a twoje wypowiedzi na temat szablonów C ++ są tak samo odpowiednie dla samego wczesnego C ++.
David Thornley,
CFront skompilował C ++ do C. Granica między preprocesorem a kompilatorem jest jasno zdefiniowana: kompilator próbuje zrozumieć swoje dane wejściowe - przez parsowanie, budowanie AST i c. - podczas gdy preprocesor nie - np. Używając tylko podstawienia tekstowego lub tokena.
Jon Purdy,
1
Myślę, że David miał na myśli to, że istnieje podstawowy podzbiór C ++ i że szablony można traktować jako pewnego rodzaju makra, które są używane do generowania programu w tym podzbiorze, który można następnie skompilować jako kolejny, oddzielny etap.
Giorgio
5

Istnieją pewne różnice; na przykład szablonów można użyć do utworzenia przeciążenia funkcji, gdy jest to potrzebne, natomiast w przypadku makr trzeba by było rozwinąć makro raz dla każdego możliwego przeciążenia, aby było widoczne dla kompilatora, aby uzyskać dużo nieużywanego kodu.

Kolejną różnicą jest to, że szablony honorują przestrzenie nazw.

Simon Richter
źródło
2

Szablony IMHO, C ++ i makra C miały rozwiązać dwa całkowicie różne problemy. Oryginalna standardowa biblioteka szablonów C ++ była mechanizmem czystego oddzielania klas kontenerów (tablic, list połączonych itp.) Od powszechnie stosowanych funkcji ogólnych (takich jak sortowanie i konkatenacja). Posiadanie abstrakcyjnych reprezentacji wydajnych algorytmów i struktur danych prowadzi do bardziej ekspresyjnego kodu, ponieważ znacznie mniej zgaduje, w jaki sposób najlepiej wdrożyć funkcję działającą na danym fragmencie danych. Makra C były znacznie bardziej zgodne z tym, co zwykle można zobaczyć w makrach Lisp, ponieważ zapewniały środki do „rozszerzenia” języka za pomocą wbudowanego kodu. Fajne jest to, że Standardowa biblioteka C ++ rozszerzyła funkcjonalność szablonów, aby pokryć ogromną większość tego, do czego używamy #define w C.

Marc
źródło