Kompilator wygeneruje kod dla każdej instancji szablonu, gdy użyjesz szablonu podczas kroku kompilacji. W procesie kompilacji i łączenia pliki .cpp są konwertowane na czysty obiekt lub kod maszynowy, który zawiera odniesienia lub niezdefiniowane symbole, ponieważ pliki .h zawarte w pliku main.cpp nie mają jeszcze implementacji YET. Są one gotowe do połączenia z innym plikiem obiektowym, który definiuje implementację twojego szablonu, dzięki czemu masz pełny plik wykonywalny a.out.
Ponieważ jednak szablony muszą być przetwarzane na etapie kompilacji w celu wygenerowania kodu dla każdej zdefiniowanej instancji szablonu, więc po prostu kompilacja szablonu osobnego od pliku nagłówkowego nie będzie działać, ponieważ zawsze idą w parze, z tego samego powodu. że każda instancja szablonu jest dosłownie nową klasą. W zwykłej klasie możesz rozdzielić .h i .cpp, ponieważ .h jest schematem tej klasy, a .cpp jest surową implementacją, więc wszelkie pliki implementacji można regularnie kompilować i łączyć, jednak przy użyciu szablonów .h jest schematem tego, jak klasa nie powinna wyglądać tak, jak powinien wyglądać obiekt, co oznacza, że szablon .cpp nie jest zwykłą zwykłą implementacją klasy, to po prostu schemat klasy, więc każda implementacja pliku szablonu .h może „
Dlatego szablony nigdy nie są kompilowane osobno i są kompilowane tylko tam, gdzie masz konkretną instancję w innym pliku źródłowym. Jednak konkretna instancja musi znać implementację pliku szablonu, ponieważ po prostu modyfikujetypename T
użycie konkretnego typu w pliku .h nie wykona zadania, ponieważ to, co .cpp jest tam do połączenia, nie mogę go później znaleźć, ponieważ pamiętam, że szablony są abstrakcyjne i nie można ich skompilować, więc jestem zmuszony aby przekazać implementację w tej chwili, więc wiem, co skompilować i połączyć, a teraz, gdy mam implementację, zostaje ona dołączona do załączonego pliku źródłowego. Zasadniczo w chwili tworzenia szablonu muszę utworzyć zupełnie nową klasę i nie mogę tego zrobić, jeśli nie wiem, jak ta klasa powinna wyglądać, gdy używam typu, który udostępniam, chyba że powiadomię kompilator implementacja szablonu, więc teraz kompilator może zastąpić T
mój typ i stworzyć konkretną klasę, która jest gotowa do kompilacji i połączenia.
Podsumowując, szablony są schematami tego, jak powinny wyglądać klasy, klasy są schematami tego, jak powinien wyglądać obiekt. Nie mogę kompilować szablonów oddzielnie od ich konkretnej instancji, ponieważ kompilator kompiluje tylko konkretne typy, innymi słowy szablony przynajmniej w C ++ są czystą abstrakcją językową. Musimy de-abstrakcyjne szablony, że tak powiem, i robimy to, dając im konkretny typ, z którym możemy sobie poradzić, aby nasza abstrakcja szablonu mogła przekształcić się w zwykły plik klasy, a z kolei można go skompilować normalnie. Oddzielenie szablonu .h pliku od szablonu .cpp nie ma znaczenia. Jest to nonsensowne, ponieważ oddzielenie .cpp i .h występuje tylko wtedy, gdy .cpp można skompilować osobno i połączyć indywidualnie z szablonami, ponieważ nie możemy ich osobno skompilować, ponieważ szablony są abstrakcją,
Znaczenie typename T
get zostało zastąpione podczas kroku kompilacji, a nie kroku łączenia, więc jeśli spróbuję skompilować szablon bez T
zastąpienia go konkretnym typem wartości, który jest całkowicie bez znaczenia dla kompilatora, w wyniku czego nie można utworzyć kodu obiektowego, ponieważ nie wiedzieć co T
jest
Technicznie możliwe jest stworzenie pewnego rodzaju funkcji, która zapisze plik template.cpp i zmieni typy, gdy znajdzie je w innych źródłach, myślę, że standard ma słowo kluczowe export
, które pozwoli ci umieścić szablony w osobnym plik cpp, ale nie tak wiele kompilatorów faktycznie to implementuje.
Na marginesie, przy tworzeniu specjalizacji dla klasy szablonu, możesz oddzielić nagłówek od implementacji, ponieważ specjalizacja z definicji oznacza, że specjalizuję się w konkretnym typie, który można kompilować i łączyć indywidualnie.