Pergunta

Eu quero criar uma estrutura que contém uma lista de mesma estrutura como esta:

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

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

Este código não está compilando. Mas quando eu substituir std::list com std::vector é bom trabalhar. Como posso fazer este trabalho com std::list?

janela de saída contém o seguinte erro.

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
Foi útil?

Solução

Se você precisa de um workround para o que parece ser um bug VC6, criar a lista dinamicamente:

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

Alguns perguntaram por que listas do mesmo tipo que os membros são permitidos (e na minha opinião, eles são) quando

Url array[5]; 

por exemplo, como um membro não seria. Eu não consigo encontrar nada no padrão também, mas sizeof( std:;list <T>) não é dependente da coisa é uma lista de. lista Suponha que foi implementado como (alguns pseudo C ++ aqui):

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

então não há tamanho desconhecido para lidar com eles. Considere o seguinte código mínimo que aborda o problema questionadores:

template <typename T> struct A {
};

struct B {
    A <B> b;
};

Eu não consigo ver qualquer razão possível que isso não deve ser legal.

Outras dicas

Você pode nos dizer o compilador que você está usando? Não há nada de intrinsecamente errado com o que você está fazendo. Eu tentei o seguinte em VS2008 SP1 e compilado nenhum problema

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

Você talvez se esqueça de incluir lista?

Editar

OP é usando o Visual Studio 6.0 e Neil foi capaz de confirmar que ele é realmente um bug no VS6

Ao contrário das afirmações nas outras respostas, é de fato não legal para instanciar qualquer recipiente padrão, incluindo std::list, com um tipo incompleto. (Para um desta, ver, por exemplo como um tipo incompleto pode ser usado como um parâmetro de modelo para vector aqui? )

Este requisito só se relaxou em C ++ 17 para std::forward_list, std::list e std::vector. Por qualquer padrão anteriormente, o código original trabalhar com versões mais recentes do VC e gcc é uma extensão não-padrão. Isto também se aplica às suas observações com std::vector.

Na pré-C ++ 17, ter portably um std::list de algum T classe como um membro da referida classe, você precisa de uma solução alternativa como std::list<T*> ou usar a biblioteca boost.container, que já portably implementa os requisitos relaxado.

Note que, mesmo em C ++ 17, você só pode instanciar o próprio modelo de classe com um tipo incompleto. O tipo deve ainda ser completa quando qualquer membro é instanciado.

Interessante - você está tentando criar um vector ou list do tipo incompleto. De um rápido olhar para o padrão, eu não consigo encontrar nada dizer se este é ou não é suposto ser permitido para tipos de contêineres incluídos na biblioteca padrão C ++. De qualquer decisão parece ser razoável:

Por que ele não pode ser permitido:. Você não pode declarar um objeto do tipo X dentro da definição de X

por exemplo. o seguinte código não compilar porque criaria uma estrutura de dados infinitamente profunda:

struct X {
    X x;
};

Por que isso pode ser permitido: A maioria dos recipientes são redimensionáveis, necessitando de um nível de engano (ponteiros) aos elementos de dados reais em prática. É legal para declarar um ponteiro-se X dentro da definição de X.

Como o último parágrafo sugere, a forma usual de contornar este problema é usar ponteiros ou referências a X. Por exemplo. os dois trechos seguintes compilar muito bem:

struct Y {
    Y* y;
};

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

Alguém (OK, eu quero dizer litb :-P) saber o que os requisitos realmente são para tipos de contêineres padrão?

O código compila perfeitamente bem com GCC 4.4 E executa perfeitamente. MSVC ++ anteriores à versão 7, não era totalmente compatível com os padrões. Você deve considerar o uso de um compilador mais recente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top