Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit specialization of function templates causes linker error

Functions.h:

#pragma once
#include <iostream>

template<class T> void TemplatedFunction(T* p) {}

template<> void TemplatedFunction<float>(float* p) {}

template<> void TemplatedFunction<char>(char* p) {}

Functions.cpp:

#include "Functions.h"

void Test()
{
    TemplatedFunction<float>(NULL);
    TemplatedFunction<char>(NULL);
}

main.cpp:

#include "Functions.h"
void Test();

int main()
{
    Test();
    return 0;
}

Build errors:

main.obj : error LNK2005: "void __cdecl TemplatedFunction<float>(float *)" (??$TemplatedFunction@M@@YAXPAM@Z) already defined in Functions.obj
main.obj : error LNK2005: "void __cdecl TemplatedFunction<char>(char *)" (??$TemplatedFunction@D@@YAXPAD@Z) already defined in Functions.obj

I know two ways to fix this:

  1. Don't include Functions.h to several .cpp files - cannot be applied in complicated project, if h-file contains some additional definitions needed in many .cpp files.

  2. Declare all templated functions as static. But this means that specialized functions appear in all .cpp files where Functions.h is included, even if they are not used, which possibly causes code duplication.

So, I see that specialized templated function behaves like non-templated function. Is there any other solution to prevent linker error without static declaration? If functions are declared static, does modern C++ compiler remove them from optimized build, if they are not used?

Edit. After reading first two answers: I don't ask here how to prevent such linker error. Assuming that I cannot move specialization to .cpp file and leave it in .h file with static or inline, does this cause code duplication and bloating in optimized build, when these functions are added to every .cpp file where .h file is included, even if they are not used?

like image 684
Alex F Avatar asked Aug 27 '14 14:08

Alex F


Video Answer


1 Answers

So, I see that specialized templated function behaves like non-templated function.

Correct.

Is there any other solution to prevent linker error without static declaration?

Yes, like any normal non-template function:

Either Define the function specializations as inline

or Declare (but do not define) the specializations in the header:

template<> void TemplatedFunction<float>(float* p);

template<> void TemplatedFunction<char>(char* p);

and define them in Functions.cpp

template<> void TemplatedFunction<float>(float* p) {}

template<> void TemplatedFunction<char>(char* p) {}

These are better options than using static, because making the functions static has other side effects, such as giving the functions different addresses in each translation unit, and making local static variables different in every translation unit. That's a semantic change, not just a solution to the linker error.

If functions are declared static, does modern C++ compiler remove them from optimized build, if they are not used?

Yes. But in any files where they are used, you will get duplicate code, making the executable larger than if there was a single definition of the function.

Assuming that I cannot move specialization to .cpp file and leave it in .h file with static ...

I can't see any good reason why that would be necessary, but anyway ...

... or inline, does this cause code duplication and bloating in optimized build, when these functions are added to every .cpp file where .h file is included, even if they are not used?

No, if they are not used in a given file they will not affect the size of the object compiled from that file.

Your question is misleading because it appears to be about templates (the title is very clearly about templates!) but whether unused inline/static functions cause code bloat is independent of whether the functions are templates or not.

If your question is simply "do unused inline and static functions affect object size?" the answer is no, for both normal functions and function templates.

like image 51
Jonathan Wakely Avatar answered Oct 17 '22 16:10

Jonathan Wakely