Ketika saya menggunakan template khusus di file objek yang berbeda, saya mendapatkan kesalahan "definisi ganda" saat menghubungkan. Satu-satunya solusi yang saya temukan melibatkan penggunaan fungsi "inline", tetapi sepertinya ada beberapa solusi. Bagaimana cara mengatasinya tanpa menggunakan kata kunci "sebaris"? Jika itu tidak memungkinkan, mengapa?
Berikut adalah contoh kode:
paulo@aeris:~/teste/cpp/redef$ cat hello.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include <iostream>
template <class T>
class Hello
{
public:
void print_hello(T var);
};
template <class T>
void Hello<T>::print_hello(T var)
{
std::cout << "Hello generic function " << var << "\n";
}
template <> //inline
void Hello<int>::print_hello(int var)
{
std::cout << "Hello specialized function " << var << "\n";
}
#endif
paulo@aeris:~/teste/cpp/redef$ cat other.h
#include <iostream>
void other_func();
paulo@aeris:~/teste/cpp/redef$ cat other.c
#include "other.h"
#include "hello.h"
void other_func()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello('a');
hi.print_hello(1);
}
paulo@aeris:~/teste/cpp/redef$ cat main.c
#include "hello.h"
#include "other.h"
int main()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello('a');
hi.print_hello(1);
other_func();
return 0;
}
paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
Akhirnya:
paulo@aeris:~/teste/cpp/redef$ make
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
other.o: In function `Hello<int>::print_hello(int)':
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)'
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: ** [all] Erro 1
Jika saya menghapus komentar "inline" di dalam hello.h, kode akan dikompilasi dan dijalankan, tetapi itu sepertinya semacam "solusi" bagi saya: bagaimana jika fungsi khusus besar dan digunakan berkali-kali? Apakah saya akan mendapatkan biner besar? Apakah ada cara lain untuk melakukan hal ini?. Jika ya, bagaimana caranya? Jika tidak, mengapa?
Saya mencoba mencari jawaban, tetapi yang saya dapatkan hanyalah "gunakan sebaris" tanpa penjelasan lebih lanjut.
Terima kasih
Jawaban:
Secara intuitif, ketika Anda sepenuhnya mengkhususkan sesuatu, itu tidak bergantung pada parameter template lagi - jadi kecuali Anda membuat spesialisasi sebaris, Anda perlu meletakkannya dalam file .cpp bukan .h atau Anda akhirnya melanggar satu aturan definisi seperti yang dikatakan David. Perhatikan bahwa ketika Anda mengkhususkan sebagian template, spesialisasi parsial masih bergantung pada satu atau beberapa parameter template, jadi mereka masih masuk dalam file .h.
sumber
hello.h
.template <typename T>
maka itu mungkin masuk ke header, dan jikatemplate<>
mungkin tidak?Kata kunci
inline
lebih tentang memberi tahu kompiler bahwa simbol akan ada di lebih dari satu file objek tanpa melanggar Aturan Satu Definisi daripada tentang sebaris sebenarnya, yang dapat diputuskan oleh kompilator untuk dilakukan atau tidak.Masalah yang Anda lihat adalah tanpa inline, fungsi tersebut akan dikompilasi di semua unit terjemahan yang menyertakan header, melanggar ODR. Menambahkan di
inline
sana adalah cara yang tepat untuk pergi. Jika tidak, Anda dapat meneruskan mendeklarasikan spesialisasi dan menyediakannya dalam satu unit terjemahan, seperti yang akan Anda lakukan dengan fungsi lainnya.sumber
Anda secara eksplisit membuat contoh template di header Anda (
void Hello<T>::print_hello(T var)
) Anda. Ini akan menciptakan banyak definisi. Anda dapat menyelesaikannya dengan dua cara:1) Buat instantiasi Anda sebaris.
2) Deklarasikan instantiation di header dan kemudian implementasikan di cpp.
sumber
Berikut adalah beberapa bagian dari standar C ++ 11 yang terkait dengan masalah ini:
Jadi jika Anda membuat beberapa spesialisasi eksplisit (alias penuh) template dalam
*.h
file, maka Anda masih perluinline
membantu Anda menyingkirkan pelanggaran ODR .sumber