【问题标题】:C++ static dispatch with custom initialization带有自定义初始化的 C++ 静态调度
【发布时间】:2019-02-26 00:27:07
【问题描述】:

我想将 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++ static bitset dispatch crtp


    【解决方案1】:

    答案是:你不能用 C++ 中的 CRTP 做到这一点。发生的事情是当Base&lt;Foo&gt; 被实例化时,Foo::bsize 还不存在。这是因为当编译器在 Foo 类上看到 Base&lt;Foo&gt; 时会发生这种情况,该类位于您的 { 之前。 没那么简单,但大体上是这样的。

    这里有一种解决方法可以做你想做的事,即将所有必要的信息捆绑在一个类中,然后将其作为模板参数提供。我不知道这个模式的名字(我见过“baggage class”,但感觉很贬义),但你可以在标准库中找到这样的示例,例如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 版本传递给BasicFooTraits 模板参数。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 2010-09-07
      • 2012-11-08
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      相关资源
      最近更新 更多