In a bit of serialization code for a project I'm working on I have a type whose size is compiler dependent. In order to deal with this, I decided to use a template specialization, which works great. Everything is resolved at compile time. The code looks a little bit like this (not the real code, just an example):
template <int size>
void
special_function()
{
std::cout << "Called without specialization: " << size << std::endl;
}
template <>
void
special_function<4>()
{
std::cout << "dword" << std::endl;
}
template <>
void
special_function<8>()
{
std::cout << "qword" << std::endl;
}
int
main()
{
special_function<sizeof(int)>();
return 0;
}
On my 32-bit system, executing the above program outputs dword
, as expected. But the whole point of doing it this way and not just doing if (sizeof(int) == 4) { ... } else if ...
is that I had hoped that the compiler would only produce code for the appropriate function. Since special_function<4>
is the only one called in this program, I expected it to be the only one generated by the compiler (gcc 4.1.2 in this case, on x86 Linux).
But that is not the observed behavior.
While it indeed works, the code for each template specialization is generated despite not being ever used. The generic definition is not generated, however.
I should mention that this is a one-step compilation, not a compilation into intermediary object files followed by a link. In that case it would seem natural to defer dead code removal to the link stage, and I know that linkers are not always terribly good at this.
Does anyone know what is going on? Is there a subtlety of template specialization I'm missing here? Lord knows the devil is in the details with C++.
EDIT: Since it's been mentioned, this behavior occurs with both -O3 and -Os.
EDIT2: Rob below suggested putting the functions in an anonymous namespace. Doing so and compiling with any level of optimization does indeed remove the dead code, which is good. But I was curious, so I tried doing the same with the following program:
namespace {
void foo() { std::cout << "Foo!" << std::endl; }
void bar() { std::cout << "Bar!" << std::endl; }
}
int
main()
{
foo();
return 0;
}
The idea here is see whether or not Rob's solution is actually related to template specializations. As it turns out, the above code compiled with optimizations turned on elides the unused definition of bar()
from the executable. So it seems that while his answer solves my immediate problem, it doesn't explain why template specializations that aren't used are compiled at all.
Does anyone know of a relevant snippet from the standard that would explain this? I always thought templates were generated only on use, but perhaps this is not so for full specializations ...