如何创建一个包含自身列表的结构?

Posted

技术标签:

【中文标题】如何创建一个包含自身列表的结构?【英文标题】:How to create a structure which contains a list of itself? 【发布时间】:2009-05-27 12:27:05 【问题描述】:

我想创建一个包含相同结构列表的结构,如下所示:

#include <list>
struct Url

    CString strUrl;
    std::list<Url> children;
;

int main()

    Url u1, u2;
    u1.children.push_back(u2);

此代码未编译。但是当我用std::vector 替换std::list 时,它工作正常。我怎样才能使它与std::list 一起工作?

输出窗口包含以下错误。

c:\program files\microsoft visual studio\vc98\include\list(29) : error C2079: '_Value' uses undefined struct 'Url'
        E:\test\Test.cpp(23) : see reference to class template instantiation 'std::list<struct Url,class std::allocator<struct Url> >' being compiled
c:\program files\microsoft visual studio\vc98\include\functional(185) : error C2079: 'value' uses undefined struct 'Url'
        c:\program files\microsoft visual studio\vc98\include\list(285) : see reference to class template instantiation 'std::binder2nd<struct std::not_equal_to<struct Url> >' being compiled
        E:\test\Test.cpp(23) : see reference to class template instantiation 'std::list<struct Url,class std::allocator<struct Url> >' being compiled

【问题讨论】:

【参考方案1】:

如果您需要解决似乎是 VC6 错误的方法,请动态创建列表:

#include <list>
#include <string>     // I don't use MFC

struct Url

    std::string strUrl;
    std::list<Url> * children;

    Url() 
       children = new std::list <Url>;
    

    ~Url() 
        delete children;
    
;

int  main()

    Url u1, u2;
    u1.children->push_back(u2);

有些人问为什么当

Url array[5]; 

例如作为会员就不会。我在标准中也找不到任何东西,但sizeof( std:;list &lt;T&gt;) 不依赖于它是一个列表的东西。假设列表被实现为(这里是一些伪 C++):

list <T> 
   listEntry <T> * first;
;

那么没有未知的大小可以处理。考虑以下解决提问者问题的最小代码:

template <typename T> struct A 
;

struct B 
    A <B> b;
;

我看不出这不合法的任何可能原因。

【讨论】:

+1,但正如我对 JaredPar 所说:你怎么这么有信心应该被允许?您当然不能在 X 的定义中声明一个 X 数组(这将导致无限大小的数据结构),那么为什么要允许 list 呢?我在标准中找不到任何东西,所以我认为某些实现允许的事实可能只是一个实现细节。想法? VC6 错误的最佳解决方法是使用在这个千年编写的编译器,并且在语言标准化之后。 ;) 请使用智能指针而不是指针。在这里,一个 std::auto_ptr 就足够了。 除非他想开始将一个 URL 分配给另一个。在这种情况下,具有合适的赋值操作和复制 ctor 的原始指针可能会更好。 这个答案不正确,容器的模板参数可能不是不完整的类型。【参考方案2】:

您能告诉我们您使用的是什么编译器吗?你所做的事情本身并没有错。我在VS2008 SP1上试过以下,编译没问题

#include <list>

struct Url

    std::string name;
    std::list<Url> children;
;

int _tmain(int argc, _TCHAR* argv[])

    Url u1,u2;
    u1.children.push_back(u2);
    return 0;

您是否忘记了包含列表?

编辑

OP 正在使用 Visual Studio 6.0,Neil 能够确认它确实是 VS6 中的一个错误

【讨论】:

@Shino,你能发布错误信息吗? VS 6.0 已知 STL 问题,您很可能遇到其中之一。 刚刚用VC6试了一下,确实有错误。确定的错误。 14.3.1 有注释“模板类型参数可能是不完整的类型 (3.9),但 17.3.3.6:2 表示未定义“如果将不完整的类型 (3.9) 用作模板参数实例化模板组件时。” 不完全确定如何解释这一点,但我猜当实例化它的任何成员时类型必须是完整的,但由于他只是创建一个指向不完整类型列表的指针,它应该是安全的。还是什么? @j_random - 我怀疑是错字 - 这是我副本中的第 17.4.3.6 节 糟糕,是错字。我的意思是 17.4.3.6。而且我认为标准容器没有任何特殊要求。当模板的任何组件被实例化时,类型必须是完整的(17.4.3.6),因此对于标准容器以及所有其他模板来说它必须是完整的。但是由于他只存储了一个指向该类型的指针,我认为此时实际上并没有实例化任何东西。我同意,如果他将 T 的列表直接存储在对象中,那将需要一个完整的类型。【参考方案3】:

与其他答案中的声明相反,使用不完整类型实例化任何标准容器(包括 std::list)确实是合法的。 (对于 language-lawyer 对此的讨论,请参阅例如 How can an incomplete type be used as a template parameter to vector here?)

此要求仅在 C++17 中对 std::forward_liststd::liststd::vector 有所放宽。对于任何较早的标准,与较新版本的 VC 和 gcc 一起使用的原始代码是非标准扩展。这也适用于您对std::vector 的观察。

在 C++17 之前的版本中,要可移植地将某个类 Tstd::list 作为所述类的成员,您确实需要像 std::list&lt;T*&gt; 这样的解决方法或使用 boost.container 库,它已经可移植地实现放宽的要求。

请注意,即使在 C++17 中,您也只能使用不完整的类型实例化类模板本身。当任何成员被实例化时,类型必须仍然是完整的。

【讨论】:

【参考方案4】:

有趣——你正在尝试创建一个不完整类型的vectorlist。快速浏览一下标准,我找不到任何说明 C++ 标准库中包含的容器类型是否允许这样做的内容。任何一项裁决似乎都是合理的:

为什么不允许这样做:您不能在 X 的定义中声明 X 类型的对象。

例如以下代码无法编译,因为它会创建一个无限深的数据结构:

struct X 
    X x;
;

为什么允许:大多数容器都是可调整大小的,在实践中需要对实际数据元素进行一定程度的间接(指针)。在X 的定义中声明指向X 的指针是合法的。

正如最后一段所暗示的,解决这个问题的常用方法是使用指向X 的指针或引用。例如。以下两个sn-ps编译就好了:

struct Y 
    Y* y;
;

struct Z 
    std::list<Z*> zl;
    std::vector<Z*> zv;
;

有没有人(好吧,我的意思是 litb :-P)知道标准容器类型的实际要求是什么?

【讨论】:

这个人的问题没有答案,只是一些观察。还有一个问题。 @Dave:我的意思是强调标准并不能保证他的代码应该可以工作——所以他的代码是不可移植的,可能在某些编译器上工作而不是在其他编译器上工作。但很公平,有很多评论,并没有过多强调这个有用的花絮。 您不能实例化具有不完整类型的标准容器。 2003 标准第 17.4.3.6 节中的最后一项。【参考方案5】:

代码在 GCC 4.4 下编译得非常好 并完美执行。版本 7 之前的 MSVC++ 并不完全符合标准。您应该考虑使用更新的编译器。

【讨论】:

C++17 之前的 std::list 类型不完整。

以上是关于如何创建一个包含自身列表的结构?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建引用自身的视图(递归)

初始化一个包含自身向量的结构

如何访问 C 中指向列表的指针结构数组?

如何创建返回列表包含字符串的类型提示?

Flutter - 如何访问 ListView.builder 中的一个元素?

如何在 Uniface 中为 json 结构创建一个列表