我可以在 C++ 中使用 "type of types" 吗?

Can I have a "type of types" in C++?

我是 C++ 的新手,但我一直在尝试在锁定期间使我的技能组合多样化。 我正在尝试使用 SFML 编写基于节点的声音处理工具。我想要一个结构来包含我所有节点的输入和输出。但是,我显然无法将任何类型连接在一起。我正在寻找类似于 Blender 对其节点类型所做的事情。 下面的屏幕录像显示了我的意思:绿色输出类型与其他输入类型不兼容。

我认为 struct NodeInOut 可能是解决这个问题的有用方法:每当我创建一个新节点时,我都会分配一个类型,并且在将节点连接在一起的逻辑中,我确保不兼容的类型不可连接。但是,每当我创建一个新的节点定义时,我都需要传入一个类型。

我对节点 class 的想法是,它的结构有点像这张仓促制作的图表。

有没有人知道如何做到这一点,或者如何以不同的方式构建它以便这不是问题?

除了 SFML 样板文件之外,我还没有编写任何代码。

是的,你可以有一个“类型的类型”。

但是,请注意用户在运行时连接节点。因此,这是一个运行时问题,不是您可以在编译时解决的问题。

换句话说,只需使用包含任何类型节点的运行时值 accept/send 并根据需要进行比较。

如果我正确理解了这个问题,那么这样的事情应该可行:

  • 特定节点继承自抽象 class Node

  • class Node 包含纯虚函数以列出 input/output 点:

    virtual std::size_t InputCount() const = 0;
    virtual const Input &GetInput(std::size_t i) const = 0;
    Input &GetInput(std::size_t i) {return const_cast<Input &>(std::as_const(*this).GetInput(i));}
    
    virtual std::size_t OutputCount() const = 0;
    virtual const Output &GetOutput(std::size_t i) const = 0;
    Output &GetOutput(std::size_t i) {return const_cast<Output &>(std::as_const(*this).GetOutput(i));}
    

    可能还有 virtual void Update() = 0;DrawGui

  • 类 派生自 Node 具有 InputOutput 对象作为成员,并覆盖 GetInputGetOutput return 那些成员。

    (奖励:您可以使用 magic_get 等反射库自动生成函数。)

  • class Input 将不得不以某种方式指向它所连接的 Output,可能是通过存储指向 Node 的指针(std::weak_ptr?)拥有连接的 Output,以及节点中那个 Output 的索引。

  • class Output 至少应包含 float value;(或其他内容,具体取决于您要支持的值)。也许你想在其中存储一个连接的 Input 列表(其中每个元素都是指向 Node 的指针加上其中 Input 的索引)。

正如下面评论中所讨论的 ,这是我的替代方案:

  • 每个节点都是(最终的,不是虚拟的)Node class

    的成员
  • 这个Nodeclass有一个std::vector<Input>和一个std::vector<Output>,代表节点的每一个输入和输出(它们可能是如果你足够努力,就会成为 const)

  • 你添加一个名为 update 的私有变量,它的类型为 std::function<void(Node &)> 或等价物(例如,你可以使用 lambda),它是一个 user-defined根据输入设置输出的更新方法,以及一个名为 Update 的 public 函数,该函数调用此节点的 update 和节点的 Update以下节点(因为它们也需要更新)

  • 然后对于Outputs你需要有一个函数来设置值(也许是一个模板函数?然后你检查类型是否正确并获得兼容的类型,也许使用 std::variants 来存储值),以及所有连接到它的 Inputs 的列表(所以可能是 std::vector<Node*, unsigned>?或者你也可以用一个替换 Node* std::weak_ptr<Node>)

  • 至于输入,您需要能够将它们连接到一个 Output,因此 Output*std::weak_ptr<Output> 都可以,但由于您需要能够有常量你可以:

    1. 还有一个std::variant来存储默认值,或者
    2. 您可以创建新的“不可见”Nodes,每个悬挂输入没有输入和一个输出,或者
    3. 您为每个可见的节点创建一个不可见的 Node,它没有输入,并且输出与目标节点的输入一样多(并将它们连接起来 one-to-one)。

这可能(可能)不是最好的解决方案,但至少它应该有效。