Adam
Adam

Reputation: 2334

Common function for classes derived from a class template

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

Answers (1)

Christophe
Christophe

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

Related Questions