具有自定义初始化的C ++静态调度

时间:2019-02-26 00:27:07

标签: c++ static bitset dispatch crtp

我想在代码的性能敏感部分中使用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函数来完成工作? (更贴近我的第一个无效解决方案) 谢谢。

1 个答案:

答案 0 :(得分:2)

答案是:您不能在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的{​​{1}}模板参数。

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