我想将CRTP用于我的代码的性能敏感部分。但是,我的基类有一个bitset,其大小取决于派生类。我希望这样的东西能起作用:
template <typename Derived>
class Base {
protected:
std::bitset<Derived::bsize> data_;
};
class Foo : public Base<Foo> {
public:
constexpr static size_t bsize = 2;
};
但是编译器抱怨道:“Foo中没有成员bsize”。我想我可以通过在基类中模板化bitset长度来解决我的问题:
template <typename Derived, size_t size>
class Base {
protected:
std::bitset<size> data_;
};
class Foo : public Base<Foo,2> { ... };
将来,我可能希望有更复杂的表达式来计算bitset长度。有没有办法使用constexpr函数完成工作? (更接近我的第一个非工作解决方案)谢谢。
答案是:你不能用C ++中的CRTP做到这一点。发生的事情是当Base<Foo>
被实例化时,Foo::bsize
还不存在。这是因为当编译器在Base<Foo>
类上看到Foo
时会发生这种情况,该类位于{
之前。它不是那么简单,但这是一般的想法。
有一种解决方法可以在此处执行您想要的操作,即将所有必要信息捆绑在一个类中,然后将其作为模板参数提供。我不知道这种模式的名称(我看过“行李类”,但感觉很贬义),但你可以在标准库中找到这样的例子,例如std::char_traits
。
class FooTraits {
constexpr static size_t bsize = 2;
};
template <class Traits = FooTraits>
class BasicFoo {
protected:
std::bitset<Traits::bsize> data_;
};
特征非常灵活 - 您可以将static constexpr
函数放入FooTraits
以计算您需要的任何内容。在您的情况下,派生类会将特定于派生类型的FooTraits
版本传递给Traits
的BasicFoo
模板参数。
值得注意的是,你的milage可能会有所不同。虽然灵活,但是特性的问题在于,想要实现FooTraits
概念的人需要确保它们实现BasicFoo
需要的所有东西,否则它们会得到一个可怕的编译错误(在C ++ 20中,这是通过concepts帮助的)。没有仔细考虑,特征可能成为事物的倾销场,这使得实施替代FooTraits
更加困难。