代码之家  ›  专栏  ›  技术社区  ›  Antoine Morrier

隐藏重载虚拟函数的模板化访问者:SFINAE on using?

  •  1
  • Antoine Morrier  · 技术社区  · 6 年前

    我正在编写一个访客模板(取决于我们想要访问的类型):

    #include <iostream>
    #include <memory>
    #include <vector>
    #include <string>
    
    class INode;
    class INodeVisitor {
    public:
        virtual void visit(INode&) = 0;
        virtual ~INodeVisitor() = default;
    };
    
    template<typename ...Ts>
    class TypedNodeVisitor;
    
    template<typename T1, typename ...Ts>
    class TypedNodeVisitor<T1, Ts...> : public TypedNodeVisitor<Ts...> {
    public:
        virtual void visit(INode &v) override {
            if(auto p = dynamic_cast<T1*>(std::addressof(v))) {
                apply(*p);
            }
    
            if constexpr(sizeof...(Ts) != 0) {
                TypedNodeVisitor<Ts...>::visit(v);
            }
        }
    
        //using TypedNodeVisitor<Ts...>::apply;
    
        virtual void apply(T1 &) = 0;
    };
    
    template<>
    class TypedNodeVisitor<> : public INodeVisitor {};
    
    class INode {
    public:
        void accept(INodeVisitor &nv) {
            nv.visit(*this);
        }
    
        virtual ~INode() = default;
    };
    
    class NodeB : public INode {};
    class NodeA : public INode {};
    
    class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
    public:
        void apply(NodeA &) override {
            std::cout << "A" << std::endl;
        }
    
        void apply(NodeB &) override {
            std::cout << "B" << std::endl;
        }
    };
    
    int main()
    {
        auto nodeA = std::make_shared<NodeA>();
        auto nodeB = std::make_shared<NodeB>();
        DrawerVisitor visitor;
        nodeA->accept(visitor);
        nodeB->accept(visitor);
    
        return 0;
    }
    

        prog.cc:49:30: note: in instantiation of template class 'TypedNodeVisitor<NodeA, NodeB>' requested here
    class DrawerVisitor : public TypedNodeVisitor<NodeA, NodeB> {
                                 ^
    prog.cc:31:18: note: hidden overloaded virtual function 'TypedNodeVisitor<NodeB>::apply' declared here: type mismatch at 1st parameter ('NodeB &' vs 'NodeA &')
        virtual void apply(T1 &) = 0;
    

    apply() 在空虚的专业化中 TypedNodeVisitor<> .

    有没有办法使用 std::enable_if using TypedNodeVisitor<Ts...>::apply

    2 回复  |  直到 6 年前
        1
  •  3
  •   max66    6 年前

    有没有一种方法可以在using上使用enable\ if TypedNodeVisitor<Ts...>::apply ?

    据我所知,你不能:你不能模板化的类型 using 所以可以使用SFINAE来启用/禁用它。

    我不认为在空的专门化中定义一个“伪造的apply定义”有什么错 TypedNodeVisitor<> “(我认为这是一个简单而优雅的解决方案)但是。。。如果你真的想避免它,你可以定义一个 TypedNodeVisitor<T0> 专业化,而不是 TypedNodeVisitor<>

    template <typename T0>
    class TypedNodeVisitor<T0> : public INodeVisitor
     {
       public: 
        virtual void visit(INode &v) override {
            if(auto p = dynamic_cast<T0*>(std::addressof(v))) {
                apply(*p);
            }
        }
    
        virtual void apply(T0 &) = 0;
     };
    

    这样你也可以避免 if constexpr 测试 visit() 成员(但你可以避免它也添加了一个假的 在里面 )

        2
  •  1
  •   David G    6 年前
    template<class...Ts>
    struct IApply{};
    template<class T0, class T1, class...Ts>
    struct IApply<T0,T1,Ts...>:
      IApply<T0>,IApply<T1,Ts...>
    {
      using IApply<T0>::apply;
      using IApply<T1,Ts...>::apply;
    };
    template<class T0>
    struct IApply<T0>{
      virtual void apply(T0&)=0;
    };
    

    template<class Base, typename ...Ts>
    class TypedNodeVisitor:public Base{};// 0 case
    
    template<class Base, typename T1, typename ...Ts>
    class TypedNodeVisitor<Base, T1, Ts...>: public TypedNodeVisitor<Base, Ts...> {
    

    现在我们可以定制我们的基地了。

    template<class...Ts>
    struct IBase: INodeVisitor, IApply<Ts...>{};
    
    template<class...Ts>
    struct ITypeNodeVisitor:TyoedNodeVisitor<IBase<Ts...>,Ts...>{};
    
    class DrawerVisitor : public ITypedNodeVisitor<NodeA, NodeB> {
    

    完成了。

    同时从TypedNodeVisitor中删除apply。