c++ 带有用于遍历树结构的模板的访问者模式

tnkciper  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(105)

我得到了一个类似“树”的结构,它表示一个简单的加法表达式。(例如2 + 4 +(3 + 5))
我使用访问者模式遍历树并找到总和。问题是我希望我的实现使用模板,这会导致一些奇怪的错误。
我需要每个子表达式的accept函数能够返回任何类型,这样我就可以执行不仅仅是整数操作

#include <iostream>
#include <vector>

#define print(x) std::cout << x << "\n"; 

class Add;
class Number;

// Basic template for visitor class

template <class T>
class Visitor {
public:
    virtual T visitAdd(Add* add) = 0;
    virtual T visitNumber(Number* num) = 0;
};

// Visitor made for adding

template <class T>
class Adder : public Visitor<T> {
public:
    T visitAdd(Add* add) override;
    T visitNumber(Number* num) override;
};

// Node types for expression tree

class Expr {
public:
    template <class T>
    virtual T accept(Visitor<T>* visitor) = 0;
};

class Add : public Expr {
public:
    Expr* left;
    Expr* right;

    Add(Expr* left, Expr* right) : left(left), right(right) {};

    template <class T>
    T accept(Visitor<T>* visitor) {
        return visitor->visitAdd(this);
    }
};

class Number : public Expr {
public:
    int value;

    Number(int value) : value(value) {};

    template <class T>
    T accept(Visitor<T>* visitor) {
        return visitor->visitNumber(this);
    }
};

template <class T>
T Adder<T>::visitAdd(Add* add) {
    return add->left->accept(this) + add->right->accept(this);
}

template <class T>
T Adder<T>::visitNumber(Number* num) {
    return num->value;
}

int main() {

    // Should represent (5 + 2) + (7 + (4 + 2))
    Expr* expression = new Add(
        new Add(
            new Number(5),
            new Number(2)
        ),
        new Add(
            new Number(7),
            new Add(
                new Number(4),
                new Number(2)
            )
        )
    );

    // Print sum as int
    Adder<int> intAdder = Adder<int>();
    print(expression->accept(&intAdder));

    // Print sum as float
    Adder<float> floatAdder = Adder<float>();
    print(expression->accept(&floatAdder));

    return 0;
}

字符串
错误:函数模板声明中不允许“virtual”(对于Expr::accept)

368yc8dk

368yc8dk1#

解决这个问题的一种方法是删除返回值并将结果保留在访问者内部。这样Visitor<T>就变成

struct Visitor {
    virtual void visitAdd(Add* add) = 0;
};

字符串
Adder也将删除返回值,并添加结果字段

template <class T>
struct Adder : public Visitor<T> {
    void visitAdd(Add* add) override { 
      add->left->accept(this);
      add->right->accept(this); }
... left as an exercise for the reader ...


并且Expr::accept也将丢弃其模板参数。在main中,您必须从Adder<int>示例中提取结果。

相关问题