首页 > 解决方案 > 隐藏重载虚函数的模板化访问者:使用 SFINAE?

问题描述

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

#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

标签: c++templatesc++17variadic-templatessfinae

解决方案


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

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

我认为在“的空专业化中定义“应用的虚假定义”并没有错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()(但你也可以避免它也添加一个假visit()的 in TypedNodeVisitor<>


推荐阅读