具有可变返回类型的 C++ 访问者模式

Luk*_*uke 5 c++ templates virtual-functions visitor-pattern

我有以下设置:

class IVisitor{
public:
    virtual SomeType visit(IVisitable& visitable) = 0;
};

class IVisitable{
public:
    virtual SomeType accept(IVisitor& visitor) = 0;
};

class ConcreteVisitor : public IVisitor{
public:
    SomeType visit(IVisitable& visitable) override {
        return calculateSomeStuff();
    }
};

class ConcertVisitable : public IVisitable{
public:
    SomeType accept(IVisitor& visitor) override {
        return visitor.visit(*this);
    }
};
Run Code Online (Sandbox Code Playgroud)

但我希望不同的访问者返回不同的类型。为此,IVisitable::accept()还应该返回不同的类型。

这将导致以下(不正确)代码:

template <typename R>
class IVisitor{
public:
    virtual R visit(IVisitable& visitable) = 0;
};

class IVisitable{
public:
    template <typename R>
    virtual R accept(IVisitor<R>& visitor) = 0;
};

class ConcreteVisitorOne : public IVisitor<int>{
public:
    int visit(IVisitable& visitable) override {
        return calculateSomeStuff();
    }
};

class ConcreteVisitorTwo : public IVisitor<bool>{
public:
    bool visit(IVisitable& visitable) override {
        return calculateSomeStuff();
    }
};

class ConcertVisitable : public IVisitable{
public:
    int accept<int>(IVisitor<int>& visitor) override {
        return visitor.visit(*this);
    }
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,这在 C++ 中是不可能的,因为虚拟函数IVistitable::accept()无法模板化。

有人知道解决这个限制的方法吗?

Ulr*_*rdt 6

几种选择:

  • 不返回任何内容,处理访问者内部的值。访问者可以完全自由地存储或处理任何返回值和类型。

  • 返回一个可变参数类型(std::anystd::variant)。请注意,使用它们需要您找出实际类型,这可能与您原来的问题有点相似。

  • 继承多个IVisitor<>接口。这甚至可能是最简单的方法,尽管它不一定很优雅。

  • 这是一个使用经典 GoF 访问者模式的基本示例 https://godbolt.org/z/n9x717o7e 看着你的代码,我意识到也许你还有其他想法,但很难说到底是什么。 (2认同)