2009-05-27 15 views
6

Chcę utworzyć strukturę, która zawiera listę samej strukturze jak poniżej:Jak utworzyć strukturę, która zawiera własną listę?

#include <list> 
struct Url 
{ 
    CString strUrl; 
    std::list<Url> children; 
}; 

int main() 
{ 
    Url u1, u2; 
    u1.children.push_back(u2); 
} 

Ten kod nie jest kompilacją. Ale kiedy zastąpię std::list z std::vector, to działa dobrze. Jak mogę sprawić, aby działało to z std::list?

Okno wyjściowe zawiera następujący błąd.

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 

Odpowiedz

6

Jeśli potrzebujesz workround za to, co wydaje się być błąd vc6, tworzyć lista dynamicznie:

#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); 
} 

Niektórzy pytali, dlaczego list tego samego typu, co członkowie są dozwolone (i moim zdaniem są one), gdy

Url array[5]; 

na przykład jako członek nie będzie. Nie mogę znaleźć niczego w standardzie, ale sizeof(std:;list <T>) nie jest zależne od rzeczy, których jest listą. Załóżmy, że lista została wprowadzona jako (niektóre pseudo C++ tutaj):

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

to nie ma nieznany rozmiar do czynienia. Rozważmy następujący minimalny kod, który odnosi się do problemu pytających:

template <typename T> struct A { 
}; 

struct B { 
    A <B> b; 
}; 

Nie widzę żadnej możliwej przyczyny, że nie powinno być legalne.

+0

+1, ale jak powiedziałem JaredPar: dlaczego jesteś tak pewny, że to powinno być dozwolone? Z pewnością nie można zadeklarować tablicy X w definicji X (mogłoby to prowadzić do nieskończonej wielkości struktury danych), więc dlaczego miałaby być dozwolona lista ? Nie mogę znaleźć niczego w standardzie, więc myślę, że fakt, który jest dozwolony w niektórych implementacjach, jest prawdopodobnie tylko szczegółem implementacji. Myśli? –

+0

Najlepszym sposobem obejścia błędów VC6 jest użycie kompilatora napisanego w tym tysiącleciu i po standaryzacji języka. ;) – jalf

+0

@j_random_hacker: Ale możesz zadeklarować wskaźnik do tablicy X w definicji X (lub po prostu wskaźnik do X). I tutaj zapisuje wskaźnik do listy. Ale nie pamiętam wszystkich szczegółów, kiedy i jak niekompletne typy są dozwolone, więc nie jestem pewien, czy to czyni je legalnymi. :) – jalf

5

Czy możesz nam powiedzieć, jakiego kompilatora używasz? Z tym, co robisz, nie ma nic nie w porządku. Próbowałem następujące na VS2008 SP1 i skompilowany bez problemu

#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; 
} 

Czy może zapomnieć do listy obejmują?

EDIT

OP jest przy użyciu programu Visual Studio 6.0 i Neil był w stanie potwierdzić, że rzeczywiście jest to błąd w VS6

+0

Używam programu Visual Studio 6.0 –

+1

@Shino, czy mógłbyś opublikować komunikat o błędzie? VS 6.0 ma znane problemy ze STL i prawdopodobnie używasz jednego z nich. – JaredPar

+0

@Shino: VS 6.0 niestety ma wiele błędów i niespójności z bardziej nowoczesnymi częściami C++ (STL, szablony itp.). Jeśli to możliwe, spróbuj uaktualnić do nowszego kompilatora - darmowe wersje Express są dostępne. –

0

Interesujące - próbujesz utworzyć vector lub list niekompletnego typu. Z szybkiego spojrzenia na standard nie mogę stwierdzić, czy jest to dozwolone, czy też nie, dla typów kontenerów zawartych w C++ Standard Library. Albo orzeczenie wydaje się być rozsądny:

Dlaczego nie może być dozwolone: ​​ Nie można zadeklarować obiekt typu X wewnątrz definicji X.

E.g. następujący kod nie skompilować, ponieważ byłoby stworzyć nieskończenie-głęboką strukturę danych:

struct X { 
    X x; 
}; 

Dlaczego to może być dozwolony: Większość pojemniki są resizeable, wymagające poziom zadnie (wskaźniki) do rzeczywistych elementów danych w praktyce. Zgłoszenie wskaźnika do X jest zgodne z definicją X.

Jak sugeruje ostatni akapit, zwykłym sposobem obejścia tego problemu jest użycie wskaźników lub odnośników do X. Na przykład. następujące dwa fragmenty skompilować dobrze:

struct Y { 
    Y* y; 
}; 

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

Czy ktoś (OK, to znaczy litb :-P) wie, jakie wymagania są rzeczywiście dla standardowych typów kontenerów?

+0

Nie ma odpowiedzi na problem mężczyzny, tylko kilka obserwacji. I pytanie. –

+0

@Dave: Chciałem podkreślić, że standard nie gwarantuje, że jego kod powinien działać - więc jego kod jest nieprzenośny, prawdopodobnie działa na niektórych kompilatorach, a nie na innych. Ale wystarczająco uczciwe, jest wiele komentarzy i niewiele miejsca na tę pożyteczną ciekawostkę. –

+1

Nie można utworzyć instancji standardowych kontenerów o niekompletnym typie. –

0

Kod doskonale współpracuje z GCC 4.4 I działa perfekcyjnie. MSVC++ przed wersją 7 nie był całkowicie zgodny ze standardami. Powinieneś rozważyć użycie nowszego kompilatora.

+0

Nie możesz mieć 'std :: list' niekompletnego typu pre-C++ 17. –

1

przeciwieństwie do roszczeń w innych odpowiedzi, to jest rzeczywiście nie prawny do wystąpienia dowolnego standardowego kontenera, w tym std::list, z niekompletną typu. (Dla omówienie tego, patrz np How can an incomplete type be used as a template parameter to vector here?)

Wymóg tylko zostanie złagodzone C++ 17 dla std::forward_list, std::list i std::vector. W przypadku każdego wcześniejszego standardu oryginalny kod współpracujący z nowszymi wersjami VC i gcc jest rozszerzeniem niestandardowym. Dotyczy to również twoich obserwacji z std::vector.

W pre-C++ 17, przenośną mieć std::list pewnej klasie T jako członek wspomnianej klasy, trzeba zrobić obejście jak std::list<T*> lub korzystania z biblioteki boost.container, który już przenośnie implementuje swobodnej wymagania .

Należy pamiętać, że nawet w C++ 17 można utworzyć tylko sam szablon klasy z niekompletnym typem. Typ musi być nadal kompletny, gdy zostanie utworzony dowolny element członkowski.

Powiązane problemy