当编译时未知返回类型时,如何避免向下转换? [英] How to avoid down-casting when return types are not known at compile time?

查看:78
本文介绍了当编译时未知返回类型时,如何避免向下转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个名为 Node 的抽象基类。

Suppose I have a abstract base class called Node.

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

    Node * leftChild, *rightChild;

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

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

I also have multiple functions (of which I'll include two for simplicity but in reality this could be any number).

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

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

For each function there is an associated class. The first is as follows.

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

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

第二个在下面。

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

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

主要,我想执行如下所示的创建方式

In main I would like to execute something like the below as a way of creating a linked list in the hopes of building an abstract syntax tree.

BinaryFunction1 testBinaryFunction1();
BinaryFunction2 testBinaryFunction2();

testBinaryFunction1.attach(&testBinaryFunction2, &testBinaryFunction2);

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

dynamic_cast 确实很丑陋,我看到它使我往后走。有没有办法避免这种情况并完全摆脱它。

The dynamic_cast is really ugly and I see it tripping me up further down the road. Is there a way to avoid this and get rid of it entirely.

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

As far as I can see Node * leftChild, * rightChild is really the problem as I believe this is where the implicit down-casting happens. I am unsure how to declare these pointers if I don't know what their types will be at compile time.

推荐答案

我的方法会看起来像这样:

My approach would look something like this:

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 在这里很合适(但是将您限制为一组编译时类型,这可能就足够了。)

I don't know what exactly you want to do with the function pointers you are currently trying to return, but it's probably got to do with evaluating an expression. That concept can go into the Node interface and can be implemented by each concrete type of node. That requires specifying a return type though, and that's not something known at the Node level. In fact, it's presumably unknown at compile-time in general - invalid user input can obviously not lead to compile-time errors, it will have to lead to run-time errors. std::variant is a good match here (but limits you to a compile-time set of types, which is probably sufficient).

然后我们可以定义例如

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

并像这样一起使用所有内容:

and use everything together like this:

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());
}

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

(Note that polymorphy requires pointers or references!)

在此处试用: https://godbolt.org/z/GNHKCy

这篇关于当编译时未知返回类型时,如何避免向下转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆