std::tuple
и using
ваши друзья.
Если вы определяете Visitable
таким образом
template <typename, typename>
class Visitable;
template<typename Derived, typename... Types>
class Visitable<Derived, std::tuple<Types...>> : public VisitableInterface<Types...> {
public:
virtual void accept(Visitor<Types...> &visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
и добавить через using
, то, что заменить идею макросъемки
using tupleT = std::tuple<IntegerElement, StringElement, BoxElement, ImageElement>;
определение ваших элементов становятся просто
class IntegerElement: public Visitable<IntegerElement, tupleT> {};
class StringElement: public Visitable<StringElement, tupleT> {};
class BoxElement: public Visitable<BoxElement, tupleT> {};
class ImageElement: public Visitable<ImageElement, tupleT> {};
Ваш пример изменен
#include <iostream>
template<typename... Types>
class Visitor;
template<typename Type>
class Visitor<Type> {
public:
virtual void visit(Type &visitable) = 0;
};
template<typename Type, typename... Types>
class Visitor<Type, Types...>: public Visitor<Types...> {
public:
using Visitor<Types...>::visit;
virtual void visit(Type &visitable) = 0;
};
template<typename... Types>
class VisitableInterface {
public:
virtual void accept(Visitor<Types...> &visitor) = 0;
};
template <typename, typename>
class Visitable;
template<typename Derived, typename... Types>
class Visitable<Derived, std::tuple<Types...>> : public VisitableInterface<Types...> {
public:
virtual void accept(Visitor<Types...> &visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
class IntegerElement;
class StringElement;
class BoxElement;
class ImageElement;
using tupleT = std::tuple<IntegerElement, StringElement, BoxElement, ImageElement>;
class IntegerElement: public Visitable<IntegerElement, tupleT> {};
class StringElement: public Visitable<StringElement, tupleT> {};
class BoxElement: public Visitable<BoxElement, tupleT> {};
class ImageElement: public Visitable<ImageElement, tupleT> {};
class RenderEngine : public Visitor<IntegerElement, StringElement, BoxElement, ImageElement>
{
public:
virtual void visit(IntegerElement& e) { std::cout << "visit Int\n"; };
virtual void visit(StringElement& e) { std::cout << "visit Str\n"; };
virtual void visit(BoxElement& e) { std::cout << "visit Box\n"; };
virtual void visit(ImageElement& e) { std::cout << "visit Img\n"; };
};
int main(void)
{
RenderEngine renderEngine;
IntegerElement intE;
StringElement strE;
BoxElement boxE;
ImageElement imgE;
renderEngine.visit(intE);
renderEngine.visit(strE);
renderEngine.visit(boxE);
renderEngine.visit(imgE);
return 0;
}
--- EDIT ---
Я стараюсь отвечать на Ваш комментарий-вопросы
почему класс шаблон Visitable; необходимо задать , прежде чем определять фактический шаблон?
Я не знаю, возможно ли это сделать проще, но ... это потому, что нам нужно «извлечь» типы из std::tuple
. Так что вам нужно общее определение (template <typename, typename>
, чтобы иметь возможность получить std::tuple<something>
тип и вам нужна специализация, так что вы можете извлечь someting
типов.
такой же ловкий трюк может быть также сделано для шаблона Visitor путем определения дополнительный шаблон, который принимает зЬй :: кортежа в качестве шаблона параметра. вы можете добавить это к вашему ответу, а также, пожалуйста?
Да, это возможно.
Но вы должны MODIF y VisitableInterface
и RenderEngine
тоже.
Большое изменение для небольшого улучшения (ИМХО); только для использования tupleT
, определяющий RenderEngine
.
Во всяком случае, ваш пример стал
#include <iostream>
template<typename>
class Visitor;
template<typename Type>
class Visitor<std::tuple<Type>> {
public:
virtual void visit(Type &visitable) = 0;
};
template<typename Type, typename... Types>
class Visitor<std::tuple<Type, Types...>>: public Visitor<std::tuple<Types...>> {
public:
using Visitor<std::tuple<Types...>>::visit;
virtual void visit(Type &visitable) = 0;
};
template<typename... Types>
class VisitableInterface {
public:
virtual void accept(Visitor<std::tuple<Types...>> &visitor) = 0;
};
template <typename, typename>
class Visitable;
template<typename Derived, typename... Types>
class Visitable<Derived, std::tuple<Types...>> : public VisitableInterface<Types...> {
public:
virtual void accept(Visitor<std::tuple<Types...>> &visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
class IntegerElement;
class StringElement;
class BoxElement;
class ImageElement;
using tupleT = std::tuple<IntegerElement, StringElement, BoxElement, ImageElement>;
class IntegerElement: public Visitable<IntegerElement, tupleT> {};
class StringElement: public Visitable<StringElement, tupleT> {};
class BoxElement: public Visitable<BoxElement, tupleT> {};
class ImageElement: public Visitable<ImageElement, tupleT> {};
class RenderEngine : public Visitor<tupleT>
{
public:
virtual void visit(IntegerElement& e) { std::cout << "visit Int\n"; };
virtual void visit(StringElement& e) { std::cout << "visit Str\n"; };
virtual void visit(BoxElement& e) { std::cout << "visit Box\n"; };
virtual void visit(ImageElement& e) { std::cout << "visit Img\n"; };
};
int main(void)
{
RenderEngine renderEngine;
IntegerElement intE;
StringElement strE;
BoxElement boxE;
ImageElement imgE;
renderEngine.visit(intE);
renderEngine.visit(strE);
renderEngine.visit(boxE);
renderEngine.visit(imgE);
return 0;
}
Что является причиной вниз голосования? – Nikopol
Я предполагаю, что пример кода поставит вопрос немного лучше. Иногда легче увидеть этот код. Также, если код мог бы скомпилировать это, также было бы хорошо, поэтому мы могли бы сначала проверить перед компилятором, не имея необходимости кодировать что-то, что может быть так, как вы его намереваетесь. – Hayt
Okey, я добавлю минимальный код, чтобы прояснить вопрос. Спасибо за ответ! :) – Nikopol