[英]Create alias for a list of types and passing it as a template parameter
我使用可变参数模板来实现访问者模式:
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 Derived, typename... Types>
class Visitable : public VisitableInterface<Types...> {
public:
virtual void accept(Visitor<Types...> &visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
class IntegerElement;
class StringElement;
class BoxElement;
class ImageElement;
class IntegerElement: public Visitable<IntegerElement, IntegerElement, StringElement, BoxElement,
ImageElement> {};
class StringElement: public Visitable<StringElement, IntegerElement, StringElement, BoxElement,
ImageElement> {};
class BoxElement: public Visitable<BoxElement, IntegerElement, StringElement, BoxElement,
ImageElement> {};
class ImageElement: public Visitable<ImageElement, IntegerElement, StringElement, BoxElement,
ImageElement> {};
class RenderEngine : public Visitor<IntegerElement, StringElement, BoxElement, ImageElement>
{
virtual void visit(IntegerElement& e) {};
virtual void visit(StringElement& e) {};
virtual void visit(BoxElement& e) {};
virtual void visit(ImageElement& e) {};
};
int main(void)
{
RenderEngine renderEngine;
return 0;
}
假设将有更多可访问的类,当从Visitable
和Visitor
模板继承时,您最终会得到很长的类型列表。 此外,如果要将LinkElement添加到此类访问者接受的可访问类型,则必须将其添加到任何位置。
由于从Visitor
和Visitable
继承时使用了相同的类型列表(除了这个类型采用了添加类型,继承自它的类的类型),我想实现更优雅的解决方案。
是否有一种更优选,更清晰的方法来为除宏之外的此类型列表定义别名?
注意:通过宏我指的是定义和使用它而不是实际的列表:
#define VISITABLE_TYPES IntegerElement, StringElement, BoxElement, ImageElement
// Add more types here
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;
}
---编辑---
我试着回答你的评论问题
为什么模板类可以访问; 在定义实际模板之前需要?
我不知道是否有可能以更简单的方式做到这一点,但是......因为我们需要从std::tuple
“提取”类型。 因此,您需要一个通用定义( template <typename, typename>
才能接收std::tuple<something>
类型,并且您需要专门化,以便您可以提取someting
类型。
通过定义一个以std :: tuple作为模板参数的附加模板,也可以为Visitor模板完成相同的巧妙技巧。 您也可以将此添加到您的答案中吗?
是的,这是可能的。
但是你也必须修改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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.