具有自定义初始化的 C++ 静态分派
C++ static dispatch with custom initialization
我想将 CRTP 用于代码的性能敏感部分。但是,我的基础 class 有一个位集,其大小取决于派生的 class。我希望这样的事情会奏效:
template <typename Derived>
class Base {
protected:
std::bitset<Derived::bsize> data_;
};
class Foo : public Base<Foo> {
public:
constexpr static size_t bsize = 2;
};
但编译器抱怨:"no member bsize in Foo"。我想我可以通过在基础 class:
中模板化位集长度来解决我的问题
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
还不存在。这是因为当编译器在您的 {
之前的 Foo
class 上看到 Base<Foo>
时,就会发生这种情况。没相当这么简单,但这是一般的想法。
这里有一个解决方法可以满足您的需求,即将所有必要的信息捆绑在 class 中,然后将其作为模板参数提供。我不知道这种模式的名称(我见过 "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_;
};
Traits 非常灵活——您只需将 static constexpr
函数放入 FooTraits
即可计算您需要的任何内容。在您的情况下,派生 class 会将 FooTraits
的派生类型特定版本传递给 BasicFoo
.
的 Traits
模板参数
值得注意的是,您的里程可能会有所不同。虽然灵活,但 traits 的问题在于想要实现 FooTraits
概念的人需要确保他们实现了 BasicFoo
需要的所有东西,否则他们将得到一个可怕的编译错误(在 C++20 中,这是通过 concepts) 帮助的。如果不仔细考虑,特征可能会变成垃圾场,这使得实施替代方案 FooTraits
更加困难。
我想将 CRTP 用于代码的性能敏感部分。但是,我的基础 class 有一个位集,其大小取决于派生的 class。我希望这样的事情会奏效:
template <typename Derived>
class Base {
protected:
std::bitset<Derived::bsize> data_;
};
class Foo : public Base<Foo> {
public:
constexpr static size_t bsize = 2;
};
但编译器抱怨:"no member bsize in Foo"。我想我可以通过在基础 class:
中模板化位集长度来解决我的问题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
还不存在。这是因为当编译器在您的 {
之前的 Foo
class 上看到 Base<Foo>
时,就会发生这种情况。没相当这么简单,但这是一般的想法。
这里有一个解决方法可以满足您的需求,即将所有必要的信息捆绑在 class 中,然后将其作为模板参数提供。我不知道这种模式的名称(我见过 "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_;
};
Traits 非常灵活——您只需将 static constexpr
函数放入 FooTraits
即可计算您需要的任何内容。在您的情况下,派生 class 会将 FooTraits
的派生类型特定版本传递给 BasicFoo
.
Traits
模板参数
值得注意的是,您的里程可能会有所不同。虽然灵活,但 traits 的问题在于想要实现 FooTraits
概念的人需要确保他们实现了 BasicFoo
需要的所有东西,否则他们将得到一个可怕的编译错误(在 C++20 中,这是通过 concepts) 帮助的。如果不仔细考虑,特征可能会变成垃圾场,这使得实施替代方案 FooTraits
更加困难。