我想将CRTP用于代码的性能敏感部分。但是,我的基类有一个位集,其大小取决于派生类。我希望这样的事情行得通:

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”。我想我也可以通过在基类中模板化位集长度来解决我的问题:
template <typename Derived, size_t size>
class Base {
protected:
    std::bitset<size> data_;
};

class Foo : public Base<Foo,2> { ... };

将来,我可能希望使用更复杂的表达式来计算位集长度。有没有办法使用constexpr函数来完成工作? (更贴近我的第一个无效解决方案)
谢谢。

最佳答案

答案是:您不能在C++中使用CRTP做到这一点。发生的是当实例化Base<Foo>时,Foo::bsize尚不存在。这是因为,当编译器在Base<Foo>之前的Foo类上看到{时,就会发生这种情况。它不是那么简单,但这是一般的想法。

这里有一个解决方法,可以将您需要的所有信息 bundle 在一个类中,然后将其作为模板参数提供。我不知道这种模式的名称(我看过“行李舱”,但感觉有点贬义),但是您可以在标准库(例如 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版本传递给TraitsBasicFoo模板参数。

值得注意的是,您的里程可能会有所不同。特质的问题是灵活的,但问题是想要实现FooTraits概念的人需要确保实现了BasicFoo需要的所有东西,否则他们将得到可怕的编译错误(在C++ 20中,这可以通过concepts来解决)。如果没有仔细考虑,特征就可能成为事物的垃圾场,这使得实现替代FooTraits变得更加困难。

10-06 07:53