我可以在 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
具有 Input
和 Output
对象作为成员,并覆盖 GetInput
和 GetOutput
return 那些成员。
(奖励:您可以使用 magic_get
等反射库自动生成函数。)
class Input
将不得不以某种方式指向它所连接的 Output
,可能是通过存储指向 Node
的指针(std::weak_ptr
?)拥有连接的 Output
,以及节点中那个 Output
的索引。
class Output
至少应包含 float value;
(或其他内容,具体取决于您要支持的值)。也许你想在其中存储一个连接的 Input
列表(其中每个元素都是指向 Node
的指针加上其中 Input
的索引)。
正如下面评论中所讨论的 ,这是我的替代方案:
每个节点都是(最终的,不是虚拟的)Node
class
的成员
这个Node
class有一个std::vector<Input>
和一个std::vector<Output>
,代表节点的每一个输入和输出(它们可能是如果你足够努力,就会成为 const)
你添加一个名为 update
的私有变量,它的类型为 std::function<void(Node &)>
或等价物(例如,你可以使用 lambda),它是一个 user-defined根据输入设置输出的更新方法,以及一个名为 Update
的 public 函数,该函数调用此节点的 update
和节点的 Update
以下节点(因为它们也需要更新)
然后对于Output
s你需要有一个函数来设置值(也许是一个模板函数?然后你检查类型是否正确并获得兼容的类型,也许使用 std::variant
s 来存储值),以及所有连接到它的 Input
s 的列表(所以可能是 std::vector<Node*, unsigned>
?或者你也可以用一个替换 Node*
std::weak_ptr<Node>
)
至于输入,您需要能够将它们连接到一个 Output
,因此 Output*
或 std::weak_ptr<Output>
都可以,但由于您需要能够有常量你可以:
- 还有一个
std::variant
来存储默认值,或者
- 您可以创建新的“不可见”
Node
s,每个悬挂输入没有输入和一个输出,或者
- 您为每个可见的节点创建一个不可见的
Node
,它没有输入,并且输出与目标节点的输入一样多(并将它们连接起来 one-to-one)。
这可能(可能)不是最好的解决方案,但至少它应该有效。
我是 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
具有Input
和Output
对象作为成员,并覆盖GetInput
和GetOutput
return 那些成员。(奖励:您可以使用
magic_get
等反射库自动生成函数。)class Input
将不得不以某种方式指向它所连接的Output
,可能是通过存储指向Node
的指针(std::weak_ptr
?)拥有连接的Output
,以及节点中那个Output
的索引。class Output
至少应包含float value;
(或其他内容,具体取决于您要支持的值)。也许你想在其中存储一个连接的Input
列表(其中每个元素都是指向Node
的指针加上其中Input
的索引)。
正如下面评论中所讨论的
每个节点都是(最终的,不是虚拟的)
的成员Node
class这个
Node
class有一个std::vector<Input>
和一个std::vector<Output>
,代表节点的每一个输入和输出(它们可能是如果你足够努力,就会成为 const)你添加一个名为
update
的私有变量,它的类型为std::function<void(Node &)>
或等价物(例如,你可以使用 lambda),它是一个 user-defined根据输入设置输出的更新方法,以及一个名为Update
的 public 函数,该函数调用此节点的update
和节点的Update
以下节点(因为它们也需要更新)然后对于
Output
s你需要有一个函数来设置值(也许是一个模板函数?然后你检查类型是否正确并获得兼容的类型,也许使用std::variant
s 来存储值),以及所有连接到它的Input
s 的列表(所以可能是std::vector<Node*, unsigned>
?或者你也可以用一个替换Node*
std::weak_ptr<Node>
)至于输入,您需要能够将它们连接到一个
Output
,因此Output*
或std::weak_ptr<Output>
都可以,但由于您需要能够有常量你可以:- 还有一个
std::variant
来存储默认值,或者 - 您可以创建新的“不可见”
Node
s,每个悬挂输入没有输入和一个输出,或者 - 您为每个可见的节点创建一个不可见的
Node
,它没有输入,并且输出与目标节点的输入一样多(并将它们连接起来 one-to-one)。
- 还有一个
这可能(可能)不是最好的解决方案,但至少它应该有效。