Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ templates, undefined reference

I have a function declared like so:

template <typename T> 
T read();

and defined like so:

template <typename T>
T packetreader::read() {
    offset += sizeof(T);
    return *(T*)(buf+offset-sizeof(T)); 
}

However, when I try to use it in my main() function:

packetreader reader;
reader.read<int>();

I get the following error from g++:

g++ -o main main.o packet.o
main.o: In function `main':
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()'
collect2: ld returned 1 exit status
make: *** [main] Error 1

Can anyone point me into the right direction?

like image 245
Daniel Sloof Avatar asked Mar 16 '09 00:03

Daniel Sloof


3 Answers

You need to use the export keyword. However, I don't think G++ has proper support, so you need to include the template function's definition in the header so the translation unit can use it. This is because the <int> 'version' of the template hasn't been created, only the <typename T> 'version.'

An easy way is to #include the .cpp file. However, this can cause problems, e.g. when other functions are in the .cpp file. It will also likely increase the compile time.

A clean way is to move your template functions into its own .cpp file, and include that in the header or use the export keyword and compile it separately.

More information on why you should try and put template function definitions in its header file (and ignore export altogether).

like image 164
strager Avatar answered Nov 02 '22 22:11

strager


The problem is that a function template is not a function. It's a template for creating functions as needed.

So for a template to work, the compiler intuitively needs two pieces of information: The template itself, and the type that should be substituted into it. This is unlike a function call, which the compiler can generate as soon as it knows that the function exists. It doesn't need to know what the function does, just that it looks like void Frobnicate(int, float), or whatever its signature is.

When you declare the function template without defining it, you're only telling the compiler that such a template exists, but not what it looks like. That's not enough for the compiler to be able to instantiate it, it has to be able to see the full definition as well. The usual solution is to put the entire template in a header that can be included where needed.

like image 41
jalf Avatar answered Nov 02 '22 20:11

jalf


The best practice with template functions is to define them in header files. They are created at compile time so compiler has to have definition around to do so.

When export for templates would be more supported this wouldn't be the case though but right now it still hardly can be used.

like image 5
vava Avatar answered Nov 02 '22 21:11

vava