Question

The project files is as this:

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

I first ran these two commands (pwd source/brain/):

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

I copied both brain.a and brain.hpp to source/parser/. Then I ran this command (pwd source/parser):

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

And I got this error:

/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

Source files:

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]

What should I do?

Was it helpful?

Solution 2

I bet you implemented the member functions of your class template brain in the .cpp file. You need to provide template definitions in the header file so that the compiler can generate the appropriate code when it sees a template instantiation. So move the contents of brain.cpp up to brain.h.

As an example, consider these three files:

  • 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);
    }
    

Each .cpp is compiled separately and then linked together. Imagine you are the compiler, and you're trying to compile main.cpp. You see that the code wants to use the test template instantiated with T as int. So now you need to generate the appropriate code for test<int>::foo, but to do that you need to have seen the function's definition. Unfortunately, you haven't seen it, so you can't compile this program.

Instead, the definition of foo should be moved into the header file to result in this two file program:

  • 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);
    }
    

Note that you should not be adding your own declarations to the std namespace:

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.

OTHER TIPS

First thing: do not add any entity to the std namespace. This gives your program Undefined Behavior.

From your message, it looks like you have added a class named brain to the std namespace. Remove brain from the std namespace and put it into some namespace of yours. The only thing you can add to the std namespace are specializations of templates which belong to the std namespace.

Secondly, unless you provide explicit instantiations of the class templates you are using throughout your program, you should put the definitions of member functions of a class template in the same header file that contains their declaration, to make sure that they are visible from the instantiation point.

Relegating them in a separate .cpp file makes it impossible for the compiler to produce code for the member functions that you are invoking from other translation units than the one which contains their definitions. This Q&A on StackOverflow may also help you.

You need to declare an instance of the brain template class with the type you require, so in brain.cpp, at the end of the file, you should put:

template class brain <long long> ;

When you compile brain.cpp, unless you have template specifiers in there, it will not create any linkable code, because it can't instantiate the template class without a type declaration. That said, when using templated classes, it is better to keep them as pure header files

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top