Как создать структуру, которая содержит список себя? - PullRequest
6 голосов
/ 27 мая 2009

Я хочу создать структуру, которая содержит список такой же структуры, например:

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

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

Этот код не компилируется. Но когда я заменяю std::list на std::vector, он работает нормально. Как я могу заставить это работать с 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

Ответы [ 5 ]

6 голосов
/ 27 мая 2009

Если вам нужна рабочая среда для того, что кажется ошибкой 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;
};

Я не вижу никакой возможной причины, по которой это не должно быть законным.

5 голосов
/ 27 мая 2009

Можете ли вы сказать нам, какой компилятор вы используете? Нет ничего плохого в том, что вы делаете. Я попробовал следующее на 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, и Нил смог подтвердить, что это действительно ошибка в VS6

1 голос
/ 07 августа 2017

Вопреки утверждениям в других ответах, действительно не законно создавать экземпляры любого стандартного контейнера, включая std::list, с неполным типом. (Для обсуждения об этом см., Например, Как неполный тип может использоваться здесь в качестве параметра шаблона для вектора? )

Это требование смягчается только в C ++ 17 для std::forward_list, std::list и std::vector. Для любого более раннего стандарта оригинальный код, работающий с более новыми версиями VC и gcc, является нестандартным расширением. Это также относится к вашим наблюдениям с std::vector.

В pre-C ++ 17, чтобы переносимо иметь std::list некоторого класса T в качестве члена упомянутого класса, вам нужен обходной путь, подобный std::list<T*>, или используйте библиотеку boost.container, которая уже переносимо реализует смягченные требования.

Обратите внимание, что даже в C ++ 17 вы можете создавать экземпляры самого шаблона класса только с неполным типом. Тип по-прежнему должен быть завершен, когда создается какой-либо элемент.

0 голосов
/ 27 мая 2009

Код прекрасно компилируется с GCC 4.4 И выполняет отлично. MSVC ++ до версии 7 не полностью соответствовал стандартам. Вы должны рассмотреть возможность использования более нового компилятора.

0 голосов
/ 27 мая 2009

Интересно - вы пытаетесь создать vector или list неполного типа. При быстром взгляде на стандарт я не могу найти ничего, говорящего, разрешено ли это или нет для типов контейнеров, включенных в стандартную библиотеку C ++. Любое решение может показаться разумным:

Почему это не может быть разрешено: Вы не можете объявить объект типа X внутри определения X.

например. следующий код не может быть скомпилирован, поскольку он создает бесконечно глубокую структуру данных:

struct X {
    X x;
};

Почему это может быть разрешено: Размер большинства контейнеров можно изменять, что на практике требует определенного уровня косвенности (указателей) для реальных элементов данных. Допустимо объявлять указатель на X внутри определения X.

Как показывает последний абзац, обычный способ обойти эту проблему - использовать указатели или ссылки на X. Например. следующие два фрагмента компилируются просто отлично:

struct Y {
    Y* y;
};

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

Кто-нибудь (хорошо, я имею в виду litb :-P) знает, каковы требования для стандартных типов контейнеров?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...