Does G ++ generate code for unused templates?

In a bit of serialization code for the project I'm working on, I have a type whose size depends on the compiler. To deal with this, I decided to use a specialized specialization that works great. Everything is allowed at compile time. The code looks a bit like this (not 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 a dword , as expected. But the whole point is to do it this way, and not just do if (sizeof(int) == 4) { ... } else if ... , so this is what I was hoping the compiler would generate code only for the corresponding function. Since special_function<4> is the only one called in this program, I expected it to be the only compiler generated (gcc 4.1.2 in this case, on x86 Linux).

But this is not observable behavior.

While it really works, the code for each specialized specialization is created, despite the fact that it has never been used. However, a general definition is not generated.

I should mention that this is a one-step compilation, not a compilation of intermediate objects into files, followed by a link. In this case, it would be natural to postpone the removal of dead code 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 that I am missing here? The Lord knows that the devil is in the details with C ++.

EDIT: as mentioned, this happens with both -O3 and -Os.

EDIT2: Rob below suggested including functions in an anonymous namespace. Doing this and compiling with any level of optimization really removes dead code, which is good. But I was curious, so I tried to do 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 to see if Rob's solution is really related to template specialization. As it turned out, the above code compiled with optimizations turned on excludes the unused definition of bar() from the executable. Therefore, it seems that although his answer solves my immediate problem, he does not explain why template specializations that are not used are compiled at all.

Does anyone know about the relevant snippet from the standard that explains this? I always thought that templates are only generated when used, but perhaps this is not the case for full specialization ...

+6
source share
2 answers

Specialization of templates in your example are functions with external communication. The compiler cannot know that they will not be called from another translation unit.

On my g ++ 4.7.2 Ubuntu system, placing templates in an anonymous namespace and compiling with -O3 or -O4 prevented the creation of an unused function.

Similarly, declaring a static function template had the desired effect.

+8
source

This is a peculiar problem. I looked a little into it, and this problem is not related to type specialization. Probably g ++ does not split unused characters by default. This makes sense if you later want to link your output to another program.

However, there are command line options that you can use to remove unused characters. See this post for more details:

How to remove unused C / C ++ characters using GCC and ld?

but also see here

Using GCC to find inaccessible functions ("dead code")

and here

Dead code detection in legacy C / C ++ project

To try this, I modified the code as follows:

 #include <iostream> void junk_function() { std::cout<<"test" << std::endl; } 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; } 

Then save this code in sp.cpp. Firstly,

 g++ -Os sp.cpp -o sp nm sp 

and got this (note, I deleted a bunch of characters for readability):

 0804879a T _Z13junk_functionv 080487b8 T _Z16special_functionILi4EEvv 080487f5 T _Z16special_functionILi8EEvv 

There seem to be two unused characters. I also tried -O1, -O2, -O3 and got the same.

Further:

 g++ -Os -fdata-sections -ffunction-sections sp.cpp -o sp -Wl,--gc-sections nm sp 

and got the following:

 0804875a T _Z16special_functionILi4EEvv 

What is it. It looks like you just need to pass the correct arguments to tell g ++ to remove unused characters. On mac, I think they have the -dead_strip option, but I don’t know why it does not work in g ++ (even if it is mentioned in the man pages. True, I did not delve into it, so be it small font that I missed).

I think the Visual C ++ linker links by default when connected, but I have not tested. Maybe someone else can call back.

+3
source

All Articles