Неопределенная ссылка на (компиляция g ++ со статической библиотекой)

Файлы проекта таковы:

source
parser
parser.cpp
parser.hpp
brain
brain.cpp
brain.hpp

Я сначала запустил эти две команды (PWD source/brain/):

g++ -c brain.cpp -o brain.o
ar rvs brain.a brain.o

Я скопировал оба brain.a а также brain.hpp в source/parser/, Затем я запустил эту команду (PWD source/parser):

g++ parser.cpp brain.a -o parser

И я получил эту ошибку:

/tmp/cceGRLZn.o: In function `main':
parser.cpp:(.text+0x1cc): undefined reference to `std::brain<long long>::brain()'
parser.cpp:(.text+0x205): undefined reference to `std::brain<long long>::init(int)'
parser.cpp:(.text+0x26b): undefined reference to `std::brain<long long>::work()'
parser.cpp:(.text+0x2a4): undefined reference to `std::brain<long long>::clear()'
parser.cpp:(.text+0x2ec): undefined reference to `std::brain<long long>::~brain()'
parser.cpp:(.text+0x322): undefined reference to `std::brain<long long>::~brain()'
/tmp/cceGRLZn.o: In function `int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)':
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x17b): undefined reference to `std::brain<long long>::push_back(long long)'
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x37a): undefined reference to `std::brain<long long>::push_back(long long)'
collect2: ld returned 1 exit status

Исходные файлы:

brain.cpp [http://ideone.com/GNUxmH][1]
brain.hpp [http://ideone.com/M2IFAI][2]
parser.cpp [http://ideone.com/fJRzhD][3]
parser.hpp [http://ideone.com/mj6dST][4]

Что я должен делать?

1

Решение

Бьюсь об заклад, вы реализовали функции-члены шаблона вашего класса brain в .cpp файл. Вам нужно предоставить определения шаблонов в заголовочном файле, чтобы компилятор мог генерировать соответствующий код, когда он видит создание шаблона. Так что переместите содержимое brain.cpp вплоть до brain.h,

В качестве примера рассмотрим эти три файла:

  • test.h

    template <typename T>
    struct test
    {
    void foo(T);
    };
    
  • test.cpp

    #include "test.h"
    template <typename T>
    void test<T>::foo(T x)
    {
    // do something with x
    }
    
  • main.cpp

    #include "test.h"
    int main()
    {
    test<int> t;
    t.foo(5);
    }
    

каждый .cpp компилируется отдельно, а затем связывается вместе. Представьте, что вы компилятор, и вы пытаетесь скомпилировать main.cpp, Вы видите, что код хочет использовать test шаблон создан с T как int, Так что теперь вам нужно сгенерировать соответствующий код для test<int>::foo, но для этого вам нужно увидеть определение функции. К сожалению, вы этого не видели, поэтому не можете скомпилировать эту программу.

Вместо этого определение foo должен быть перемещен в заголовочный файл, чтобы в результате появилась эта двух файловая программа:

  • test.h

    template <typename T>
    struct test
    {
    void foo(T);
    };
    
    // Alternatively, you can define this up in the class definition
    void test<T>::foo(T x)
    {
    // do something with x
    }
    
  • main.cpp

    #include "test.h"
    int main()
    {
    test<int> t;
    t.foo(5);
    }
    

Обратите внимание, что вы не должны добавлять свои собственные объявления в std Пространство имен:

Поведение программы на C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std если не указано иное.

1

Другие решения

Первым делом: не добавляйте ни одного объекта в std Пространство имен. Это дает вашу программу Неопределенное поведение.

Из вашего сообщения похоже, что вы добавили класс с именем brain к std Пространство имен. Удалить brain от std пространство имен и поместите его в какое-то ваше пространство имен. Единственное, что вы можете добавить к std пространство имен специализаций шаблонов, которые принадлежат std Пространство имен.

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

Отнесение их в отдельный .cpp file делает невозможным для компилятора генерировать код для функций-членов, которые вы вызываете из других модулей перевода, кроме того, который содержит их определения. Это Q&А на StackOverflow может также помочь вам

3

Вам нужно объявить экземпляр класса шаблона мозга с нужным вам типом, поэтому в файле brain.cpp в конце файла вы должны указать:

template class brain <long long> ;

Когда вы компилируете brain.cpp, если у вас там нет спецификаторов шаблонов, он не создаст никакого связанного кода, потому что не может создать экземпляр класса шаблона без объявления типа. Тем не менее, при использовании шаблонных классов их лучше хранить в виде чистых заголовочных файлов.

1