【问题标题】:Forward declaration for recursive data structure递归数据结构的前向声明
【发布时间】:2015-05-17 13:47:24
【问题描述】:

在我写 Delphi 的时候,有一个 TStringList,它基本上是一个字符串映射到 Delphi 的通用 TObject。使用这种结构,我可以通过在其中一个字符串键上放置另一个 TStringList 来轻松地创建一个递归的层次结构:

ParentStringList["somekey"] = "just a string value";
ParentStringList["anotherkey"] = SomeChildStringList;

问题是,我如何在 C++ 中实现相同的功能?

我现在拥有的是:

typedef boost::variant< std::string, my_dictionary > my_variant;
typedef std::map < std::string, my_variant > my_dictionary;

...这显然是圆形的。

我可以在不将内容包装在结构中(我可以转发声明)或不使用指针(编译器知道其大小)的情况下做到这一点吗?

【问题讨论】:

  • struct X { X x; }; -- 没有。
  • 您对指针的厌恶在 C++ 中是一种非常好的态度,但在这种特殊情况下有点夸大其词。我猜 Delphi 实现也会在内部用指针解决这个问题。如果我是你,我会使用基于指针的解决方案(可能使用 std::unique_ptr)并将所有内容都很好地包装在一个具有完全无指针接口的类中。

标签: c++ recursion data-structures


【解决方案1】:

这种方法可行:

struct my_variant;
typedef map<string,my_variant> my_dict;
struct my_variant: variant<string, my_dict>
{};

虽然有一些问题:

  • 这需要允许未完全定义的模板参数的容器(特别是std::map)。使用 C++98,这是明确禁止的,我不确定在以后的 C++ 版本中是否取消了这一点。
  • 从容器公开派生通常不是一个好主意,请自行研究其原因以及它们如何应用于您的程序。使用包含而不是派生将是一种更安全的选择,或者是私有派生的中间方式,但这会破坏这种方法提供的有用的 IS-A 关系。

【讨论】:

  • 似乎 gcc-12 / C++20 终于解决了这个问题。没有指针的递归可以很好地编译。 gcc-11.2(撰写本文时的最新稳定版)仍然失败。
【解决方案2】:

尝试使用vectors。我以前在我的程序中将它们用作外部数据库的内部表示,作为数据结构。

【讨论】:

  • 这是不正确的——std::vector 不能保证允许递归数据结构(尽管实际上所有理智的实现都支持它)。但更糟糕的是,这对 OP 没有帮助,因为他们想使用 dynamic 值类型。
  • 你的意思是任意数据类型吗?请解释一下“动态”?
  • “动态”是指“动态类型”的通常含义,即实际使用的类型仅在运行时才知道,而不是在编译时。这与“任意”不同,因为类型仍然可以静态限制为所有可能类型的明确定义的子集。
  • 我仍然相信向量在这里适用。在同一个循环中访问两个不同的向量将保留访问具有不同类型的数据结构的功能。至于运行时已知的类型,肯定有另外一种方式,我承认我不知道如何实现这种动态数据类型。
【解决方案3】:

Boost.Variant documentation 涵盖了这种情况。如果不使用指针或其他类似的包装器,您将无法做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 2017-04-05
    • 2016-07-14
    相关资源
    最近更新 更多