Шаблоны C++ , undefined reference to

386
21 февраля 2017, 18:05

stack.cpp

//stack.cpp
#include "stack.h"
template <class T>
Stack<T>::Stack()
{
    top = nullptr;
}
template <class T>
void Stack<T>::push(T arg)
{
    Node* temp = new Node;
    temp->value = arg;
    temp->next = top;
    top = temp;
}
template <class T>
T Stack<T>::pop()
{
    if (top != nullptr)
    {
        T result = top->value;
        Node* temp = top;
        top = top->next;
        delete temp;
        return result;
    } else
        return 0;
}
template <class T>
Stack<T>::~Stack()
{
    while (top != nullptr)
        pop();
}

stack.h

//stack.h
#ifndef PROJECT_STACK_H
#define PROJECT_STACK_H
template <class T>
class Stack
{
private:
    struct Node
    {
        T value;
        Node* next;
    };
    Node* top;
public:
    Stack();
    void push(T arg);
    T pop();
    ~Stack();
};

#endif //PROJECT_STACK_H

//main.cpp примерно следующего содержания:

Stack <char> s;
s.push('a');

компилирую через g++ так: g++ -std=c++11 main.cpp stack.cpp

Получаю следующие ошибки:

/tmp/ccvtzAEt.o:main.cpp:(.text+0x1b): undefined reference to `Stack<char>::Stack()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x1b): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::Stack()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x2c): undefined reference to `Stack<char>::push(char)'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x2c): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::push(char)'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x3d): undefined reference to `Stack<char>::push(char)'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x3d): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::push(char)'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x49): undefined reference to `Stack<char>::pop()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x49): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::pop()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x66): undefined reference to `Stack<char>::pop()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x66): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::pop()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x9b): undefined reference to `Stack<char>::~Stack()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0x9b): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::~Stack()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0xae): undefined reference to `Stack<char>::~Stack()'
/tmp/ccvtzAEt.o:main.cpp:(.text+0xae): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Stack<char>::~Stack()'
collect2: ошибка: выполнение ld завершилось с кодом возврата 1

То есть undefined reference to Stack<char>::Stack() и undefined reference to Stack<char>::push(char) и undefined reference to Stack<char>::~Stack()

В чем проблема? Заранее огромное спасибо!

Answer 1

Ну откуда же при компиляции stack.cpp компилятору знать, что где-то, в совсем другом файле вам понадобится Stack<char>?

Не выносите реализацию шаблонов в отдельный файл, оставляйте ее в заголовочном файле.

Answer 2

Либо не выносите определения шаблонов в отдельный файл (т.е. реализуйте все в заголовочном файле), либо не забывайте включать этот отдельный файл повсеместно, как включаются обычные заголовочные файлы.

На практике у обоих подходов есть свои поклонники. Но при этом давать файлу реализации расширение .cpp не принято - это все таки включаемый, а не отдельно компилируемый файл.

Скармливать ваш файл реализации непосредственно компилятору (g++ stack.cpp) бесполезно: определения шаблонов не порождают кода, в чем вы сможете убедиться взглянув на сгенерированный из stack.cpp объектный файл - он будет пуст.

P.S. Теоретически, вы можете оставить все как есть, но добавить в stack.cpp явные инстанциации вашего шаблона для всех требуемых типов аргументов. Т.е. в вашем случае достаточно добавить в stack.cpp строчку

template Stack<char>;

и все сразу заработает в оригинальном виде, при компиляции через ваше g++ -std=c++11 main.cpp stack.cpp. Но, как вы сами понимаете, в общем случае это - не жизнеспособный подход, а специальная фича, предназначенная совсем для других целей.

READ ALSO
QDirIterator изменить dir

QDirIterator изменить dir

Есть функция getFileInfo

291
Кубическая интерполяция [требует правки]

Кубическая интерполяция [требует правки]

Набор аргументов для которых необходимо найти интерполируемые значения(t1):

391
Перегрузка оператора + для сложения 2 массивов

Перегрузка оператора + для сложения 2 массивов

Доброго времени суток! Нужно перегрузить оператор + для сложение двух двумерных массивовПыталась перегрузить так, но это вызывает исключение

304
Интерполяция на сетку Вороного

Интерполяция на сетку Вороного

Подскажите библиотеку на C++ в которой реализован метод интерполяции с регулярной сетки на сетку ВороногоКак я понял нужно искать все пересечения...

235