gpt4 book ai didi

c++ - 为类型列表创建别名并将其作为模板参数传递

转载 作者:可可西里 更新时间:2023-11-01 18:39:27 25 4
gpt4 key购买 nike

我正在使用可变参数模板来实现访问者模式:

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;
}

假设将有更多的可访问类,当从 VisitableVisitor 模板继承时,您最终会得到一长串类型。此外,如果要将 LinkElement 添加到此类访问者接受的可访问类型中,则必须在所有位置添加它。

因为从 VisitorVisitable 继承时使用相同的类型列表(除了这个采用附加类型,继承的类的类型从它),我想实现一个更优雅的解决方案。

除了宏之外,是否有更可取、更简洁的方法来为这个类型列表定义别名?

注意:通过宏,我指的是定义定义和使用它而不是实际列表:

#define VISITABLE_TYPES IntegerElement, StringElement, BoxElement, ImageElement
// Add more types here

最佳答案

std::tupleusing是你的 friend 。

如果定义 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;
}

--- 编辑 ---

我试着回答你的评论问题

why was the template class Visitable; needed before defining the actual template?

我不知道是否有可能以更简单的方式做到这一点,但是......这是因为我们需要从 std::tuple 中“提取”类型.因此,您需要一个通用定义( template <typename, typename> 才能接收 std::tuple<something> 类型,并且您需要一个专门化以便提取 someting 类型。

the same neat trick can be also done for the Visitor template by defining an additional template that takes a std::tuple as template parameter. Can you add this to your answer as well, please?

是的,这是可能的。

但是你得修改VisitableInterfaceRenderEngine也是。

一点改进的大变化(恕我直言);仅供使用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;
}

关于c++ - 为类型列表创建别名并将其作为模板参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39242178/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com