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

问题描述 投票:2回答:1

我想将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++ static bitset dispatch crtp
1个回答
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版本传递给TraitsBasicFoo模板参数。

值得注意的是,你的milage可能会有所不同。虽然灵活,但是特性的问题在于,想要实现FooTraits概念的人需要确保它们实现BasicFoo需要的所有东西,否则它们会得到一个可怕的编译错误(在C ++ 20中,这是通过concepts帮助的)。没有仔细考虑,特征可能成为事物的倾销场,这使得实施替代FooTraits更加困难。

© www.soinside.com 2019 - 2024. All rights reserved.