All the material I've read on Curiously Recurring Template Pattern seems to one layer of inheritance, ie Base
and Derived : Base<Derived>
. What if I want to take it one step further?
#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;
}
How can I rewrite this code to compile without errors and display
C
B
Using c.get().print() and b.get().print() ?
Motivation: Suppose I have three classes,
class GuiElement { /* ... */ };
class Window : public GuiElement { /* ... */ };
class AlertBox : public Window { /* ... */ };
Each class takes 6 or so parameters in their constructor, many of which are optional and have reasonable default values. To avoid the tedium of optional parameters, the best solution is to use the Named Parameter Idiom.
A fundamental problem with this idiom is that the functions of the parameter class have to return the object they're called on, yet some parameters are given to GuiElement, some to Window, and some to AlertBox. You need a way to write this:
AlertBox box = AlertBoxOptions()
.GuiElementParameter(1)
.WindowParameter(2)
.AlertBoxParameter(3)
.create();
Yet this would probably fail because, for example, GuiElementParameter(int) probably returns GuiElementOptions&, which doesn't have a WindowParameter(int) function.
This has been asked before, and the solution seems to be some flavor of the Curiously Recurring Template Pattern. The particular flavor I use is here.
It's a lot of code to write every time I create a new Gui Element though. I've been looking for ways to simplify it. A primary cause of complexity is the fact that I'm using CRTP to solve the Named-Parameter-Idiom problem, but I have three layers not two (GuiElement, Window, and AlertBox) and my current workaround quadruples the number of classes I have. (!) For example, Window, WindowOptions, WindowBuilderT, and WindowBuilder.
That brings me to my question, wherein I'm essentially looking for a more elegant way to use CRTP on long chains of inheritance, such as GuiElement, Window, and Alertbox.