Reputation: 2334
I have a program with the following class hierarchy:
struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };
template<typename T>
class Base
{
public:
int fun(int i);
};
template<typename T>
int Base<T>::fun(int i)
{
return 42 * i;
}
class A : public Base<TYPE_ONE>
{
public:
void another_fun()
{
fun(1);
}
} a;
class B : public Base<TYPE_TWO>
{
public:
void another_fun()
{
fun(2);
}
} b;
int main()
{
a.another_fun();
b.another_fun();
}
As you can see the fun
doesn't depend on the type. Unfortunately compiler is generating two fun
methods. One for each type.
$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
0000000000001174 W B::another_fun()
0000000000001198 W Base<TYPE_ONE>::fun(int)
00000000000011b0 W Base<TYPE_TWO>::fun(int)
Is there a way to force compiler to generate only one common function for both classes?
I see that I could try to workaround this by making fun
static and adding default argument to the template. Something like:
template<typename T=TYPE_ONE>
class Base
{
public:
static int fun(int i);
};
class A : public Base<TYPE_ONE>
{
public:
void another_fun()
{
Base<>::fun(1);
}
} a;
class B : public Base<TYPE_TWO>
{
public:
void another_fun()
{
Base<>::fun(2);
}
} b;
With this compiler generates only one fun
method:
$ nm --demangle ./a.out | grep fun
0000000000001150 W A::another_fun()
000000000000116e W B::another_fun()
000000000000118c W Base<TYPE_ONE>::fun(int)
But is there a cleaner solution for this issue?
Upvotes: 2
Views: 91
Reputation: 73376
The following defines two distinct types, that happen to have exactly the same implementation:
struct TYPE_ONE { int i; };
struct TYPE_TWO { int i; };
This misleads to think that fun()
should share the same code.
But in reality, this is a very exceptional circumstance. Because the two types could share a symbol i
with a different memory layout, that would require a different machine code to perform the apparently identical i*42.
struct TYPE_ONE { int i; };
struct TYPE_TWO { int k,i; };
You could even have the case of different types, where again, the machine code would be completely different and could not be shared:
struct TYPE_ONE { int i; };
struct TYPE_TWO { double i; };
Of course, the compiler could recognize that the types have an identical layout and make the effort of using some common code. But it's not at all an obligation.
If there is a common part in the template class with fixed types, you should refactor that common part into a non-template base to the template class. For example:
struct RealBase {
int i;
int fun(int i);
};
struct TYPE_ONE : RealBase {};
struct TYPE_TWO : RealBase {};
and adapt A and B accordingly. Here there is one RealBase, whatever template you build upon it. And your compiler would naturally have only one RealBase implementation.
Upvotes: 3