如何创建一个包含自身列表的结构?
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 <T>)
不依赖于它是一个列表的东西。假设列表被实现为(这里是一些伪 C++):
list <T>
listEntry <T> * first;
;
那么没有未知的大小可以处理。考虑以下解决提问者问题的最小代码:
template <typename T> struct A
;
struct B
A <B> b;
;
我看不出这不合法的任何可能原因。
【讨论】:
+1,但正如我对 JaredPar 所说:你怎么这么有信心应该被允许?您当然不能在 X 的定义中声明一个 X 数组(这将导致无限大小的数据结构),那么为什么要允许 list您能告诉我们您使用的是什么编译器吗?你所做的事情本身并没有错。我在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_list
、std::list
和 std::vector
有所放宽。对于任何较早的标准,与较新版本的 VC 和 gcc 一起使用的原始代码是非标准扩展。这也适用于您对std::vector
的观察。
在 C++17 之前的版本中,要可移植地将某个类 T
的 std::list
作为所述类的成员,您确实需要像 std::list<T*>
这样的解决方法或使用 boost.container 库,它已经可移植地实现放宽的要求。
请注意,即使在 C++17 中,您也只能使用不完整的类型实例化类模板本身。当任何成员被实例化时,类型必须仍然是完整的。
【讨论】:
【参考方案4】:有趣——你正在尝试创建一个不完整类型的vector
或list
。快速浏览一下标准,我找不到任何说明 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
类型不完整。以上是关于如何创建一个包含自身列表的结构?的主要内容,如果未能解决你的问题,请参考以下文章