能给我一张“票”吗;“类型的类型”;在C++;? 我对C++非常陌生,但我一直在尝试在锁定期间多样化我的技能集。 我正在尝试使用SFML编写一个基于节点的声音处理工具。我希望有一个包含所有节点输入和输出的结构。然而,我显然无法将任何类型连接在一起。我希望做一些类似于Blender对其节点类型所做的事情。 下面的屏幕记录显示了我的意思:绿色输出类型与其他输入类型不兼容。

能给我一张“票”吗;“类型的类型”;在C++;? 我对C++非常陌生,但我一直在尝试在锁定期间多样化我的技能集。 我正在尝试使用SFML编写一个基于节点的声音处理工具。我希望有一个包含所有节点输入和输出的结构。然而,我显然无法将任何类型连接在一起。我希望做一些类似于Blender对其节点类型所做的事情。 下面的屏幕记录显示了我的意思:绿色输出类型与其他输入类型不兼容。 ,c++,sfml,C++,Sfml,我认为struct NodeInOut可能是这个问题的有用解决方案:每当我创建一个新节点时,我都会分配一个类型,在将节点连接在一起的逻辑中,我确保不兼容的类型不可连接。但是,无论何时创建新节点定义,我都需要传入一个类型 我对Node类的想法是,它的结构有点像这个匆忙制作的图 有没有人对如何做到这一点有什么想法,或者如何以不同的方式构建它,使其不成为问题 除了SFML样板文件之外,我还没有编写任何代码。是的,您可以有一个“类型的类型” 但是,请注意,用户在运行时连接节点。因此,这是一个运行时问题

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

我对Node类的想法是,它的结构有点像这个匆忙制作的图

有没有人对如何做到这一点有什么想法,或者如何以不同的方式构建它,使其不成为问题

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

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

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


换句话说,只需使用包含节点接受/发送的任何类型的运行时值,并根据需要对其进行比较。

如果我正确理解了这个问题,类似这样的方法应该可以:

  • 特定节点继承自抽象
    类节点

  • 类节点
    包含纯虚拟函数,用于列出输入/输出点:

    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));}
    
    virtualstd::size\t InputCount()const=0;
    虚拟常量输入&GetInput(std::size\u ti)常量=0;
    Input&GetInput(std::size_t i){return const_cast(std::as_const(*this).GetInput(i));}
    虚拟std::size\u t OutputCount()常量=0;
    虚拟常量输出&GetOutput(std::size\u ti)常量=0;
    Output&GetOutput(std::size_t i){return const_cast(std::as_const(*this).GetOutput(i));}
    
    可能类似于
    virtualvoidupdate()=0
    DrawGui

  • 节点派生的类将
    Input
    Output
    对象作为成员,并重写
    GetInput
    GetOutput
    以返回这些成员

    (额外好处:您可以使用反射库(例如)自动生成函数。)

  • 类输入
    必须以某种方式指向它所连接的
    输出
    ,可能是通过将指针(
    std::weak_ptr
    ?)存储到拥有连接的
    输出的
    节点
    ,以及节点中该
    输出的索引

  • 类输出
    应至少包含
    浮点值(或其他,取决于您希望支持的值)。可能您需要在其中存储一个连接的
    输入的列表(其中每个元素都是指向
    节点的指针,加上其中
    输入的索引)


如以下评论所述,以下是我的备选方案:

  • 每个节点都是(最终的,不是虚拟的)
    节点
    类的成员

  • 这个
    节点
    类有一个
    std::vector
    和一个
    std::vector
    ,表示节点的每个输入和输出(如果您足够努力,它们可能会成为常量)

  • 您添加了一个名为
    update
    的私有变量,该变量的类型为
    std::function
    或等效变量(例如,您可以使用lambdas),它是一种用户定义的更新方法,用于根据输入设置输出,并添加了一个名为
    update
    的公共函数,这是一个调用此节点的
    update
    和以下节点的
    update
    的函数(因为它们也需要更新)

  • 然后,对于
    输出
    s,您需要一个函数来设置值(可能是一个模板函数?然后检查类型是否正确并获得一个兼容的类型,可能使用
    std::variant
    s来存储值),以及连接到它的所有
    输入
    s的列表(因此,
    std::vector
    可能?或者您也可以用
    std::weak\u ptr
    替换
    节点*

  • 至于输入,您需要能够将它们连接到一个
    输出
    ,因此
    输出*
    std::weak_ptr
    应该可以工作,但由于您需要能够拥有常量,您可以:

  • 还有一个
    std::variant
    来存储默认值,或者
  • 您可以创建新的“不可见”
    节点
    s,其中没有输入,每个悬空输入有一个输出,或者
  • 为每个可见的节点创建一个不可见的
    节点
    ,该节点没有输入,输出的数量与目标节点的输入数量相同(并将它们一一连接)

这也许(可能)不是最好的解决方案,但至少它应该能起作用。

我不是这个解决方案的真正粉丝,首先是因为
const\u cast
s(尽管经过更多的思考,我想不出一个方法来纠正它……),其次是因为
弱ptr
:为什么不是简单的
输出*
?输出还应该记住
输入*
向量,而不是连接的节点和输入索引(OP想要连接到多个输入…。@rajdakin“
弱ptr
:为什么不是简单的
输出*
?”如果它是一个
弱\u ptr
,那么删除一个节点很容易:只需删除它,连接到它的节点就会自动断开连接。但是如果它是一个普通指针,则必须迭代所有连接的节点并手动断开连接(考虑到