Весь материал, который я прочитал на 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
В
Использование 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).
Ранее это было , и это решение кажется некоторым вкусом шаблона Curiously Recurring Template. Особый вкус, который я использую, здесь.
Это много кода, чтобы писать каждый раз, когда я создаю новый элемент Gui. Я искал способы упростить его. Основной причиной сложности является тот факт, что я использую CRTP для решения проблемы с Именованным параметром-Идиомом, но у меня есть три слоя не два (GuiElement, Window и AlertBox) и мой текущее обходное решение в четыре раза превышает количество классов, которые у меня есть. (!) Например, Window, WindowOptions, WindowBuilderT и WindowBuilder.
Это подводит меня к моему вопросу, в котором я ищу более элегантный способ использования CRTP в длинных цепочках наследования, таких как GuiElement, Window и Alertbox.