Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Function Template, Undefined Symbol for Architecture [duplicate]

Tags:

c++

templates

Can someone please explain to me why the following won't compile?, and hopefully the obvious thing that I have missed...

functions.hpp:

template<typename T> string vector_tostr(std::vector<T> v);

functions.cpp:

template<typename T> string vector_tostr(std::vector<T> v){
    std::stringstream ss;
    std::string thestring = "";
    if(v.size() > 0){
        ss << "[";
        for(size_t i = 0; i < v.size(); i++){
            if(i != 0)
                ss << " ";
            ss << v[i];
        }
        ss << "]";
        thestring = ss.str();
    }
    return thestring;
}

main.cpp

#include "functions.hpp"
int main(int argc, char *argv[]){
   vector<int> thevector;
   thevector.push_back(1);
   thevector.push_back(2);

   string result = vector_tostr(thevector);
   //I have also tried vector_tostr<int>(thevector)
}

The cryptic error I am getting as follows:

Undefined symbols for architecture x86_64: "std::basic_string, std::allocator > vector_tostr(std::vector >)", referenced from: _main in main.o ld: symbol(s) not found for architecture x86_64 collect2: error: ld returned 1 exit status make: * [main] Error 1

like image 578
Nicholas Hamilton Avatar asked May 26 '14 03:05

Nicholas Hamilton


2 Answers

You are not allowed to seperate the declaration and definition of a templated function in the same way that you would a normal function (declaration in '.hpp' file, definition in '.cpp' file). There are a couple of ways you can get around that.

You can declare AND define the function in the same place in the header file.

OR

You could try this, in a file called functions.inl:

template<typename T> 
inline string vector_tostr(std::vector<T> v){
    std::stringstream ss;
    std::string thestring = "";
    if(v.size() > 0){
        ss << "[";
        for(size_t i = 0; i < v.size(); i++){
            if(i != 0)
                ss << " ";
            ss << v[i];
        }
        ss << "]";
        thestring = ss.str();
    }
    return thestring;
}

Then, at the end of the header file (functions.hpp), type this in:

#include "functions.inl"

.inl is the file extension for the inline header file. You can use this to seperate the declaration and definition of templated functions.

like image 83
Dennis Avatar answered Sep 30 '22 00:09

Dennis


Templates are instantiated in compile time. What the compiler does is create one overloaded method for each template argument value that is used in the code. For example, using int and double as template argument will create two overloaded methods from the same definition, only vary in argument type. So compiler must be able to see the definition while compiling. You can do this in several ways

  1. Fully defined in header
  2. Defined in for ex. .impl file and include it in the declaring header
  3. Explicitly instantiated with template parameter in a .cpp file, in that case only the instantiated versions can be used.
like image 29
Rakib Avatar answered Sep 30 '22 01:09

Rakib