2009-06-20 8 views
31

Próbuję połączyć z biblioteką współdzieloną z klasą szablonów, ale daje mi ona "błędy niezdefiniowanych symboli". Skondensowałem problem do około 20 linii kodu.C++ Shared Library with Templates: Niezdefiniowane symbole error

shared.h

template <class Type> class myclass { 
    Type x; 
public: 
    myclass() { x=0; } 
    void setx(Type y); 
    Type getx(); 
}; 

shared.cpp

#include "shared.h" 
template <class Type> void myclass<Type>::setx(Type y) { x = y; } 
template <class Type> Type myclass<Type>::getx() { return x; } 

main.cpp

#include <iostream> 
#include "shared.h" 
using namespace std; 

int main(int argc, char *argv[]) { 
    myclass<int> m; 
    cout << m.getx() << endl; 
    m.setx(10); 
    cout << m.getx() << endl; 
    return 0; 
} 

ten sposób skompilować lib wym:

g++ -fPIC -c shared.cpp -o shared.o 
g++ -dynamiclib -Wl,-dylib_install_name -Wl,libshared.dylib -o libshared.dylib shared.o 

A główny program:

g++ -c main.cpp 
g++ -o main main.o -L. -lshared 

Tylko uzyskać następujące błędy:

Undefined symbols: 
"myclass<int>::getx()", referenced from: 
    _main in main.o 
    _main in main.o 
"myclass<int>::setx(int)", referenced from: 
    _main in main.o 

Jeśli usunąć 'szablon' rzeczy w shared.h/cpp, i zastąpić je tylko "int", wszystko działa dobrze. Ponadto, jeśli po prostu skopiuję &, wkleję kod klasy szablonu bezpośrednio do main.cpp i nie będę łączył się z biblioteką współdzieloną, wszystko będzie działać poprawnie.

Jak mogę uzyskać taką klasę szablonów, aby działała przez współdzieloną bibliotekę?

Używam MacOS 10.5 z GCC 4.0.1.

+0

Duplikat: http://stackoverflow.com/questions/999358/undefined-symbols-linker-error-with-simple-template-class/999383#999383 –

Odpowiedz

34

Oprócz innych odpowiedzi można jawnie tworzyć instancje klas szablonów. Jest to przydatne tylko wtedy, gdy wiesz wcześniej, jakie typy mogą przyjmować parametry szablonu. Inicjujesz szablon we wszystkich tych typach w bibliotece.

Na Twój przykład kompilacji, wystarczy dodać następujące do końca shared.cpp:

// Instantiate myclass for the supported template type parameters 
template class myclass<int>; 
template class myclass<long>; 

Ten instancję szablonu z type = int i umieszcza kod instancja w udostępnionej biblioteki. Dodaj tyle instancji jawnych, ile potrzebujesz, dla wszystkich typów, których potrzebujesz.

Ponownie, jeśli chcesz mieć możliwość wystąpienia szablonu z dowolnym parametrem Type, potem musi dodanie definicji w pliku nagłówka, tak że kompilator zna kod źródłowy szablonu przy uruchamianiu go w inne jednostki kompilacji.

+2

To jest dokładnie to, czego szukałem. Dziękuję bardzo! Dla odniesienia do innych osób z tym samym problemem: Dodaj linie tworzenia instancji szablonu na końcu pliku shared.cpp. – nolk

+0

To świetnie, ale co, jeśli mam dwa pliki źródłowe_, a nie jedno, jak robi to OP? Gdzie powinienem dodać te linie? – ForceBru

+0

@ForceBru: W każdym z nich. Sugeruję plik źródłowy, który odpowiada plikowi nagłówkowemu, który definiuje szablon. – Cookie

16

Definicje funkcji szablonów muszą znajdować się w plikach nagłówkowych. Przenieś definicje z shared.cpp na shared.h.

Nie można tego skompilować do biblioteki współdzielonej, a następnie do niej linkować. To po prostu nie działa w ten sposób.

+2

Czyli niemożliwe jest posiadanie wspólnej biblioteki z szablonami? – nolk

+2

Wręcz przeciwnie, jest to absurdalnie łatwe. Po prostu umieść go w pliku nagłówkowym i udostępnij. Nie potrzebujesz nawet kompilatora;) Szablony nie są kompilowane dopóki nie zostaną utworzone, więc jeśli umieścisz szablon w pliku .cpp i skompilujesz go jako bibliotekę współdzieloną, kod szablonu zostanie po prostu usunięty. Definicja szablonu musi być widoczna dla użytkownika. – jalf

+0

Czy jesteś absolutnie pewien? Ponieważ obecnie pracuję z biblioteką współdzieloną, która tworzy instancje szablonów podczas kompilacji. Kod jest niewidoczny dla użytkownika, ale można go użyć. Problemy z kompilacją mogą powstać, gdy miksujesz specjacje wymagające generowania i inne, które już zostały wygenerowane. Ale poza tym, że działa dobrze. Testowane za pomocą g ++ i msvc. – Michael

5

Należy również uwzględnić implementację klas szablonów w plikach nagłówkowych. Jest to ograniczenie szablonów w C++. Tak więc włącz współdzielony.cpp z głównego (#include) lub po prostu przenieś kod z shared.cpp w shared.h

1

Kompilator musi zobaczyć cały kod szablonu, aby mógł wygenerować odpowiedni kod dla rzeczywisty typ, którego chcesz użyć. Powinieneś umieścić cały kod w swoim .h. plik.