Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding C++ explosive instantiations of template classes that take int parameters

Tags:

c++

templates

Let's say I have a C++ class:

template<int N>
class Text {
    public:
        Text() { }
        char _buf[N];
};

It simply encapsulates a C string.

Now, let's say I write a method that will take another Text object, with a length M and copy its contents into this object.

template<int N>
class Text {
    public:
        Text() { }
        char _buf[N];

        template<int M> void copy(const Text<M> &t) {
            strncpy(_buf, t.cstr(), N - 1);
            _buf[N - 1] = '\0';
        }            
};

Is this going to cause an explosion of duplicated object code where the only difference are the constants N and M used, especially if I use this copy method with objects that have lots of different N and M ?

Since the method itself doesn't depend on M at all, is there another way to approach this such that I avoid this explosion of duplicated object code?

like image 269
Ana Avatar asked Apr 10 '16 14:04

Ana


2 Answers

The most obvious approach is to factor the common bits into a base class, e.g.:

class TextBase {
public:
    char* text;
    int   n;
    TextBase(char* text, int N): text(text), n(N) {}
    void copy(const TextBase &t) {
        strncpy(this->text, t.text, n - 1);
        this->text[n - 1] = '\0';
    }  
};
template<int N>
class Text: public TextBase {
public:
    Text(): TextBase(_buf, N) { }
    char _buf[N];
};

It trades object size for a potential improvement in code size. It must be obvious because it was the first thing coming to my mind while still waking up. Instead of traveling in terms of a base taking the parameter in a type-erase form avoids the need for extra storage, e.g. (this approach came to my mind when being a bit further away from waking up):

template<int N>
class Text {
public:
    Text() { }
    char _buf[N];
    operator char const*() const { return this->_buf; }
    void copy(char const* source) {
        strncpy(this->_buf, source, N - 1);
        this->_buf[N - 1] = '\0';
    }
};
like image 113
Dietmar Kühl Avatar answered Nov 16 '22 17:11

Dietmar Kühl


As already mentioned the solution could be a base class with a pure virtual method to get the buffer. There are no additional attribute required and _bufcould be privat.

Something like this:

class TextBase {
public:
    virtual const char* cstr() const =0;
};

template<int N>
class Text: public TextBase {
public:
    Text() { }
    void copy( TextBase &t) {
      strncpy(_buf, t.cstr(), N - 1);
     _buf[N - 1] = '\0';    }  

protected:
  virtual const char* cstr() const {
    return _buf;
    };
private:
    char _buf[N];
// ...
}
like image 32
hr_117 Avatar answered Nov 16 '22 18:11

hr_117