避免使用int参数的模板类的C++爆炸性实例化

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

本文关键字:C++ 爆炸性 实例化 int 参数      更新时间:2023-10-16

假设我有一个C++类:

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

它只是封装了一个C字符串。

现在,假设我编写了一个方法,它将采用另一个长度为MText对象,并将其内容复制到该对象中。

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] = '';
        }            
};

这是否会导致重复对象代码的爆炸,其中唯一的区别是使用的常量NM,特别是如果我对具有许多不同NM的对象使用copy方法?

由于该方法本身根本不依赖于M,有没有其他方法可以避免重复对象代码的爆炸?

最明显的方法是将公共位因子化为基类,例如:

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] = '';
    }  
};
template<int N>
class Text: public TextBase {
public:
    Text(): TextBase(_buf, N) { }
    char _buf[N];
};

它用对象大小来换取代码大小的潜在改进。这一定很明显,因为这是我醒来时第一个想到的事情。与以类型擦除形式获取参数的基数不同,避免了对额外存储的需要,例如(当我离醒来有点远的时候,我想到了这种方法):

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] = '';
    }
};

如前所述,解决方案可以是一个带有纯虚拟方法的基类来获取缓冲区。不需要额外的属性,_buf可能是私有的。

类似这样的东西:

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] = '';    }  
protected:
  virtual const char* cstr() const {
    return _buf;
    };
private:
    char _buf[N];
// ...
}

总的来说,我认为C++11引入了extern template来实现这一点:

显式实例化声明(外部模板)防止隐式实例化:否则会导致隐式实例化必须使用显式实例化程序中其他地方提供的定义(通常另一个文件:这可以用来减少编译时间)

然而,对于您的用例,您需要为N和M的所有组合显式实例化Text::copy,所以这似乎不可行,Dietmar的答案将是一个更好的选择。