我一直在学习c++20概念,作为CRTP模板设计的一种替代方案,用于静态多态性(对于那些不知道我在说什么的人,这里有一个很好的资源:https://www.fluentcpp.com/2020/09/11/replacing-crtp-static-polymorphism-with-concepts/)
CRTP的好处是你可以在基类中有一个变量,然后在子类中使用它。下面是一个工作示例,其中shared是共享变量。通过同样的逻辑,我们可以在派生类中调用基类的构造函数和方法。
template <class TImpl>
class Base {
private:
TImpl &impl = static_cast<TImpl &>(*this);
friend TImpl;
int shared = 0;
public:
void say_hello() { impl.do_say_hello(); }
};
class Derived : public Base<Derived> {
friend Base<Derived>;
void do_say_hello() {
shared = 3;
cout << "Hello " << shared << endl;
}
};
int main() {
Derived d;
d.say_hello();
}
然而,这就是我被c++ 20概念卡住的地方。我可以很容易地从基类调用派生类方法,但反之亦然,感觉有点像反向多态。有人知道我如何调用基类方法并在派生类中使用基类的变量与概念化的静态多态吗?
1条答案
按热度按时间zysjyyx41#
CRTP是一个C工具,用于在C中实现mixin的概念。mixin是一种将一些泛型功能注入到特定类型的接口中的方法。因此,这涉及到两段独立的代码:通用功能和注入该功能的接口。
这篇文章有效地提出了一种通过自由函数进行mixin的方法,本质上是实现定制点习惯用法的蹩脚形式(然后将其呈现为一个发现,而不仅仅是基于
concept
的std::begin
版本,就像std::ranges::begin
一样)。定制点在通信方面通常是单向的。通用定制点函数可以检查它正在扩充的接口,但是该接口本身不能与通用功能交互。至少,不容易并且不能以非公开的方式。
相比之下,CRTP允许轻松的双向通信。(模板基类)可以通过将
this
强制转换为模板参数来调用派生类函数(C23使这种方法更容易)。由于是派生类,被注入的类可以与基类通信,如果基类为此目的公开protected
接口成员。本文提出的中间形式(其中泛型功能是派生类,注入的目标是基类)也主要是单向的:泛型到目标。CRTP强制转换之所以有效,是因为基类被“给定”了派生类类型。模板示例化规则允许派生类类型以某种方式使用,尽管该类型在继承点不完整。
所以当你把基类变成一个没有派生类名的非模板类时,你就切断了它执行强制转换的能力。这意味着像这样颠倒层次结构会使mixin通信成为单向的。尽管C23的技巧确实允许你重新获得双向通信。