我在 Curiously Recurring Template Pattern 上读过的所有材料似乎都是一层继承,即Base
和Derived : Base<Derived>
. 如果我想更进一步怎么办?
#include <iostream>
using std::cout;
template<typename LowestDerivedClass> class A {
public:
LowestDerivedClass& get() { return *static_cast<LowestDerivedClass*>(this); }
void print() { cout << "A\n"; }
};
template<typename LowestDerivedClass> class B : public A<LowestDerivedClass> {
public: void print() { cout << "B\n"; }
};
class C : public B<C> {
public: void print() { cout << "C\n"; }
};
int main()
{
C c;
c.get().print();
// B b; // Intentionally bad syntax,
// b.get().print(); // to demonstrate what I'm trying to accomplish
return 0;
}
如何重写此代码以编译而不会出现错误并显示
乙
_
使用 c.get().print() 和 b.get().print() 吗?
动机:假设我有三个班级,
class GuiElement { /* ... */ };
class Window : public GuiElement { /* ... */ };
class AlertBox : public Window { /* ... */ };
每个类在其构造函数中接受 6 个左右的参数,其中许多是可选的并且具有合理的默认值。为了避免可选参数的乏味,最好的解决方案是使用命名参数惯用语。
这个习惯用法的一个基本问题是参数类的函数必须返回它们被调用的对象,但是一些参数被提供给 GuiElement,一些给 Window,还有一些给 AlertBox。你需要一种方法来写这个:
AlertBox box = AlertBoxOptions()
.GuiElementParameter(1)
.WindowParameter(2)
.AlertBoxParameter(3)
.create();
然而这可能会失败,因为例如 GuiElementParameter(int) 可能返回 GuiElementOptions&,它没有 WindowParameter(int) 函数。
以前有人问过这个问题,解决方案似乎是某种奇怪的重复模板模式。我使用的特殊口味是here。
不过,每次我创建一个新的 Gui 元素时都要编写很多代码。我一直在寻找简化它的方法。复杂性的一个主要原因是我使用 CRTP 来解决 Named-Parameter-Idiom 问题,但我有三层而不是两层(GuiElement、Window 和 AlertBox),并且我当前的解决方法是我拥有的类数量的四倍. (!) 例如,Window、WindowOptions、WindowBuilderT 和 WindowBuilder。
这让我想到了我的问题,我本质上是在寻找一种更优雅的方式来在长继承链上使用 CRTP,例如 GuiElement、Window 和 Alertbox。