首页 > 解决方案 > 在编译时不知道返回类型时如何避免向下转换?

问题描述

假设我有一个名为Node.

class Node
{
public:
    Node() {
        leftChild = NULL;
        rightChild = NULL;
    };

    Node * leftChild, *rightChild;

    void attach(Node * LC, Node * RC) {
        leftChild = LC;
        rightChild = RC;
    };
};

我还有多个功能(为简单起见,我将包括其中两个,但实际上这可以是任何数字)。

float add(float a, float b){return a+b;}
bool gt(float a, float b){return a>b;}

每个函数都有一个关联的类。第一个如下。

class BinaryFunction1 : public Node
{
public:
    BinaryFunction1() {
    };

    float(*)(float, float) addition(){
        return add
    };
}

第二个在下面。

class BinaryFunction2 : public Node
{
public:
    BinaryFunction2() {
    };

    bool(*)(float, float) greaterthan(){
        return gt
    };
}

总的来说,我想执行以下类似的方法来创建链接列表,以期构建抽象语法树。

BinaryFunction1 testBinaryFunction1();
BinaryFunction2 testBinaryFunction2();

testBinaryFunction1.attach(&testBinaryFunction2, &testBinaryFunction2);

dynamic_cast<BinaryFunction2 *>(testBinaryFunction1.leftChild)->greaterthan()(2.0, 4.0)

dynamic_cast真的很难看,我看到它让我在路上走得更远。有没有办法避免这种情况并完全摆脱它。

据我所知,这Node * leftChild, * rightChild确实是问题所在,因为我相信这是隐式向下转换发生的地方。如果我不知道编译时它们的类型是什么,我不确定如何声明这些指针。

标签: c++linked-listabstract-syntax-treedowncast

解决方案


我的方法看起来像这样:

using TypedValue = std::variant<int, float, bool>;

using BinaryFunc = std::function<TypedValue(TypedValue, TypedValue)>;

struct Node
{
public:
    Node() {
        leftChild = nullptr;
        rightChild = nullptr;
    };

    virtual ~Node() = default;

    Node * leftChild, *rightChild;

    void attach(Node * LC, Node * RC) {
        leftChild = LC;
        rightChild = RC;
    };

    virtual TypedValue evaluate() = 0;
};


struct BinaryFuncNode : public Node
{
    BinaryFuncNode(BinaryFunc func) : Node(), binaryFunc(func) {}

    BinaryFunc binaryFunc;

    TypedValue evaluate() override
    {
        return binaryFunc(leftChild->evaluate(), rightChild->evaluate());
    }
};

struct ConstantNode : public Node
{
    ConstantNode(TypedValue val) : Node(), value(val) {}

    TypedValue value;

    TypedValue evaluate() override
    {
        return value;
    }
};

我不知道您到底想对当前尝试返回的函数指针做什么,但这可能与评估表达式有关。该概念可以进入Node接口,并且可以由每种具体类型的节点实现。但是,这需要指定返回类型,而这在该Node级别上是未知的。事实上,它可能在编译时一般是未知的——无效的用户输入显然不会导致编译时错误,它必须导致运行时错误。std::variant在这里是一个很好的匹配(但将您限制为一组编译时类型,这可能就足够了)。

然后我们可以定义例如

// Function that can only add integers (throws otherwise)
BinaryFunc addI = [](TypedValue lhs, TypedValue rhs)
{
    return std::get<int>(lhs) + std::get<int>(rhs);
};

并像这样一起使用所有东西:

int main()
{
    auto cnode = std::make_unique<ConstantNode>(10);
    auto bfnode = std::make_unique<BinaryFuncNode>(addI);
    bfnode->attach(cnode.get(), cnode.get());
    return std::get<int>(bfnode->evaluate());
}

(请注意,多态需要指针或引用!)

在这里玩一下:https ://godbolt.org/z/GNHKCy


推荐阅读