Pytanie Szablony C ++, niezdefiniowane odniesienie


Mam funkcję deklarowaną tak:

template <typename T> 
T read();

i zdefiniowane tak:

template <typename T>
T packetreader::read() {
    offset += sizeof(T);
    return *(T*)(buf+offset-sizeof(T)); 
}

Jednak gdy próbuję użyć go w mojej funkcji main ():

packetreader reader;
reader.read<int>();

Dostaję następujący błąd z g ++:

g++ -o main main.o packet.o
main.o: In function `main':
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()'
collect2: ld returned 1 exit status
make: *** [main] Error 1

Czy ktoś może wskazać mi właściwy kierunek?


28
2018-03-16 00:50


pochodzenie


możliwy duplikat Niezdefiniowane odniesienie do szablonu funkcji, gdy jest używane z ciągiem (GCC) - outis


Odpowiedzi:


Musisz użyć export słowo kluczowe. Nie uważam jednak, że G ++ ma odpowiednie wsparcie, więc musisz umieścić definicję funkcji szablonu w nagłówku, aby jednostka tłumaczeniowa mogła z niej korzystać. To dlatego, że <int> "wersja" szablonu nie została utworzona, a jedynie <typename T> 'wersja.'

Prosta droga to #include plik .cpp. Może to jednak powodować problemy, np. gdy inne funkcje znajdują się w pliku .cpp. Prawdopodobnie zwiększy to również czas kompilacji.

Czystym sposobem jest przeniesienie funkcji szablonu do własnego pliku .cpp i uwzględnienie go w nagłówku lub Użyj export słowo kluczowe i skompiluj je osobno.

Więcej informacji o tym, dlaczego powinieneś spróbować umieścić definicje funkcji szablonów w pliku nagłówkowym (i zignorować export całkowicie).


24
2018-03-16 00:53



Czy byłby to dobry pomysł, aby przenieść mój kod packet.cpp do pliku packet.h i zmienić jego nazwę na coś takiego jak "packet.hpp", jak często widziałem używane w boost? - Daniel Sloof
@Daniel, Tylko jeśli wszystkie twoje funkcje są funkcjami szablonu. W przeciwnym razie możesz uciec z przeniesieniem niektórych funkcji i zachowaniem pliku .cpp. - strager


Problem polega na tym, że szablon funkcji nie jest funkcją. Jest to szablon do tworzenia funkcji w razie potrzeby.

Aby szablon działał, kompilator intuicyjnie potrzebuje dwóch informacji: samego szablonu i typu, który powinien zostać w nim zamieniony. W przeciwieństwie do wywołania funkcji, którą kompilator może wygenerować, gdy tylko wie, że funkcja istnieje. Nie musi wiedzieć, co robi funkcja, tylko że wygląda void Frobnicate(int, float)lub jakikolwiek jest jego podpis.

Kiedy deklarujesz szablon funkcji bez definiowania go, mówisz tylko kompilatorowi, że taki szablon istnieje, ale nie jak to wygląda. To nie wystarczy, aby kompilator mógł go utworzyć, musi również zobaczyć pełną definicję. Zwykłym rozwiązaniem jest umieszczenie całego szablonu w nagłówku, który można dołączyć w razie potrzeby.


12
2018-03-16 01:00





Najlepszą praktyką z funkcjami szablonu jest definiowanie ich w plikach nagłówkowych. Są one tworzone w czasie kompilacji, więc kompilator musi mieć definicję, aby to zrobić.

Gdy export szablony byłyby bardziej obsługiwane, ale tak się nie stało, ale w tej chwili wciąż nie można ich używać.


4
2018-03-16 00:58



Nie polecam używania export. Według parashift.com/c++-faq-lite/templates.html#faq-35.14, został odrzucony ze standardu C ++ 0x. - uckelman


Czy ich każdy kompilator obsługuje osobną kompilację?

Jak wiem, powszechną praktyką jest deklarowanie i wdrażanie funkcji szablonu w pliku nagłówkowym


0
2018-03-16 01:01



Chyba nie wierzę w Comeau. I nowoczesna wersja MSVC moc ale sam tego nie sprawdziłem. - vava
Najnowszy VS2008 nie obsługuje jeszcze słowa kluczowego eksportu. Wygląda na to, że członkowie MS zarezerwowali to słowo kluczowe dla przyszłej pomocy: ostrzeżenie C4237: słowo kluczowe "eksport" nie jest jeszcze obsługiwane, ale zarezerwowane do użycia w przyszłości - Baiyan Huang