Wie eine Struktur zu schaffen, die eine Liste von selbst enthält?
Frage
Ich möchte eine Struktur schaffen, die eine Liste der gleichen Struktur wie folgt enthält:
#include <list>
struct Url
{
CString strUrl;
std::list<Url> children;
};
int main()
{
Url u1, u2;
u1.children.push_back(u2);
}
Dieser Code kompiliert nicht. Aber wenn ich std::list
mit std::vector
ersetzen funktioniert es gut. Wie kann ich diese Arbeit mit std::list
machen?
Ausgabefenster enthält die folgenden Fehler.
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
Lösung
Wenn Sie eine workround für benötigen, was scheint ein VC6 Fehler zu sein, erstellen Sie die Liste dynamisch:
#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);
}
Einige gefragt haben, warum Listen von der gleichen Art wie Mitglieder sind erlaubt (und meiner Meinung nach sind sie), wenn
Url array[5];
zum Beispiel als Mitglied nicht sein. Ich kann nichts im Standard finden entweder, aber sizeof( std:;list <T>)
ist nicht abhängig von der Sache ist es eine Liste. Angenommen Liste wurde als (einige Pseudo-C ++ hier) implementiert:
list <T> {
listEntry <T> * first;
};
dann gibt es keine unbekannte Größe zu behandeln. Betrachten Sie den folgenden minimalen Code, der den Fragesteller Problem behandelt:
template <typename T> struct A {
};
struct B {
A <B> b;
};
Ich kann nicht jeden möglichen Grund sehen, dass dies nicht legal sein sollte.
Andere Tipps
Können Sie uns sagen, welchen Compiler Sie verwenden? Es ist nichts falsch mit dem, was Sie tun. Ich habe versucht, die folgenden auf VS2008 SP1 und es kein Problem kompiliert
#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;
}
Haben Sie vielleicht vergessen Liste enthalten?
Bearbeiten
OP wird mit Visual Studio 6.0 und Neil war in der Lage zu bestätigen, dass es sich tatsächlich um einen Fehler in VS6
Im Gegensatz zu den Behauptungen in den anderen Antworten, es ist in der Tat nicht Rechts jede Standard-Container zu instanziiert, einschließlich std::list
, mit einem unvollständigen Typ. (Für eine sprach Anwalt Diskussion getaggt hierzu siehe zB wie ein unvollständiger Typ kann als Template-Parameter verwendet werden, hier Vektor? )
Diese Anforderung nur in C ++ 17 für std::forward_list
, std::list
und std::vector
entspannt wird. Für jeden früheren Standard, ist der ursprüngliche Code mit neueren Versionen von VC und gcc arbeitet eine Nicht-Standard-Erweiterung. Dies gilt auch für Ihre Beobachtungen mit std::vector
.
In Pre-C ++ 17, portably eine std::list
einer Klasse T
hat als Mitglied der Klasse, Sie brauchen eine Abhilfe wie std::list<T*>
oder die boost.container Bibliothek verwenden, die bereits portably die entspannten Anforderungen implementiert.
, dass auch in C ++ 17, Sie können nur die Klassenvorlage instanziiert selbst mit einem unvollständigen Typ. Der Typ muss noch vollständig sein, wenn jedes Mitglied instanziiert wird.
Interessant - Sie versuchen, ein vector
oder list
unvollständigen Typen zu erstellen. Von einem kurzen Blick auf den Standard, kann ich nichts zu sagen, ob dies oder soll nicht in der C ++ Standard Library enthalten für Containertypen zugelassen werden. Entweder Urteil scheint vernünftig zu sein:
Warum es nicht erlaubt werden könnte. Sie können nicht ein Objekt vom Typ X
innerhalb der Definition von X
erklären
z. der folgende Code nicht kompilieren, weil es eine unendlich tiefe Datenstruktur schaffen würde:
struct X {
X x;
};
Warum es erlaubt werden könnte: Die meisten Container sind vergrößerbar, es muss eine Dereferenzierungsebene (Zeiger) auf den tatsächlichen Datenelemente in der Praxis. Es ist legal einen Zeiger-to-X
innerhalb der Definition von X
zu erklären.
Wie der letzte Absatz schlägt vor, die übliche Art und Weise, um dieses Problem zu bekommen, ist Zeiger oder Verweise zu verwenden, um X
. Z.B. die folgenden zwei Schnipsel kompilieren ganz gut:
struct Y {
Y* y;
};
struct Z {
std::list<Z*> zl;
std::vector<Z*> zv;
};
Hat jemand (OK, ich meine litb :-P) wissen, was die Anforderungen sind eigentlich für Standard-Container-Typen?
Der Code sehr gut mit GCC 4.4 kompiliert Und führt perfekt. MSVC ++ vor Version 7 war nicht völlig standardkonform. Sie sollten mit einem neueren Compiler berücksichtigen.