Some people here told it's not possible and some people here told it might be possible to have one version of machine code for all different template arguments of a templated function, so I thought it would be profitable to open a thread regarding this specific matter, if there is not such possibility that's it, if there is, in what situations can we count on this? An example that was specifically considered in both mentioned threads is below:
template<size_t num>
struct Elements{
public:
SomeType elements[num];
};
template<size_t num>
void print(const Elements<num> & elements,size_t size){
//all instances do exactly same thing and with regard to Size that determines the size of object
}
and of course there's pass by value version also:
template<size_t num>
void print(const Elements<num> elements,size_t size){
//all instances do exactly same thing and with regard to Size that determines the size of object
}
A smart linker can recognize when two different function bodies are identical and combine them together into one symbol. This is called "COMDAT folding" in MSVC and "duplicate stripping" most other places. For example, the following two functions might compile identically on PPC, although they take different types, because the types are the same size and behave identically in the given situation.
template<typename T>
GetLowBit( T foo ) { return T & 1; }
GetLowBit<unsigned long>(ulong x); // compiles to "li r4, 1 ; and r3, r3, r4 ; blr "
GetLowBit<signed long>(long x); // also compiles to "li r4, 1 ; and r3, r3, r4 ; blr "
and so the linker can make both of their "names" point to the same place, as it were, so that a call to GetLowBit<unsigned long>
goes to the same address as a call to GetLowBit<signed long>
. So, in general, it's possible to fold together different template instantiations of functions that all operate on identical type sizes in identical ways. (In particular, containers that store pointers or enums tend to get folded together.)
This doesn't just happen for template functions. Some linkers can notice when any two functions have identical bodies, and merge them. In particular I see that MSVC tends to collapse every virtual function that does nothing but return into one uber-function, eg for
class A
{
virtual void nothing() {};
}
class B
{
virtual void empty() {};
}
I often see (in the disassembler while debugging something else) that the vtable entries for nothing
and empty
both point to the same function body, which in turn is just a ret
.
Can you count on this? No. This is a feature that a smart linker might provide for functions when it notices them. Your linker might be stupid — there's a lot of lousy compilers out there. It might only happen if you supply certain command arguments. It may happen for some functions but not others for reasons known only to the linker. It may even differ from build to build depending on what else is in the program.
So in general, yes this can happen, and when it does, it can be a nice savings in executable size. But you can't count on it happening unless you are very familiar with your linker and all its features.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With