1

Suppose I have a class SecondTimer that counts seconds and notifies listener, assuming that listener has a special method onTimer() that accept event from timer:

template <class TName>
class SecondTimer
{
public:
    SecondTimer() : listener(nullptr), stime(0), time(1000), isStarted(false) {}

    void init(TName * _listener, int _stime)
    {
        GASSERT(_listener && "The listener can not be NULL");
        listener = _listener;
        stime = _stime;
        time = 1000;
        isStarted = false;
        listener->onTimer(stime);
    }
    inline void start() { isStarted = true; }
    inline void stop() { isStarted = false; }
    void Process(int dtime)
    {
        if (!isStarted)
            return;

        time -= dtime;
        if (time <= 0)
        {
            int ds = 1 - time / 1000;
            time = time % 1000 + 1000;
            stime -= ds;
            listener->onTimer(stime);
            //
            if (stime <= 0)
            {
                isStarted = false;
            }
        }
    }

private:
    TName * listener;
    int stime, time;
    bool isStarted;
};

I want to use it as template for 1000 different classes that implements the onTimer(int) member function.

What really happens when program will be built? Will the compiler duplicate the Init() and Process() functions for all 1000 different classes?

msrd0
  • 7,816
  • 9
  • 47
  • 82
pi314159
  • 157
  • 1
  • 9
  • If your code really uses those 1000 classes yes. Also, if you have such number of classes, means that is something really wrong with your code. – Javi Sep 11 '14 at 21:19
  • @JaviV: I don't think the OP is actullay instantiating the template 1000 times. They are just making a point: will the compiler replicate this code a gazillion times? Or will it be smart? – rodrigo Sep 11 '14 at 21:25
  • I know, What I mean is that I am sure that in those cases it possible to generalize somehow. – Javi Sep 11 '14 at 21:27

2 Answers2

3

Yes. The compiler will instantiate the whole class once for every class you use it with.

That is what is sometimes called template bloat. There are techniques to partially avoid it, and modern compilers sometimes do some clever tricks. But at the end of the day there will be a lot of duplicated code.

There are some compilers out there (I don't remember which ones that, if they happen to compile two identical functions, byte to byte, they will merge them into only one. This is technically illegal in C++, because the pointers to these functions will compare equal when they should not. But then many functions from template classes will be merged. Unfortunately, in your example only the constructor, start() and stop() will qualify, as the other ones use the template class so most likely they will generate different code.

And for this kind of problems you have to consider if it is worth it to use templates or to write a base class with a virtual function (an interface). There is a tradeoff between solving the conceptually virtual call to onTimer during runtime (slower & smaller) or during compile time (faster & bigger).

For example:

struct TName
{
    virtual void onTimer() =0;
};

class SecondTimer //no template bloat!
{
   /*...*/
};

PS: I was going to add some information here about which compilers do the merge, but then I found this answer that explains it perfectly fine.

Community
  • 1
  • 1
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • I'd expect they have a trick that even if they "merge" they can provide a unique address for each one. Not hard to give them each a 1op thunk. – Mooing Duck Sep 12 '14 at 00:24
1

Will compiler duplicate Init() and Process() functions for all 1000 different classes?

Yes. This is exactly what will happen. The compiler will instantiate the whole code for a class just as if you had written all of this manually. Some optimization are however possible.

4pie0
  • 29,204
  • 9
  • 82
  • 118