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