Исправление ошибки boost::optional неопределенного типа

Я пытался создать двунаправленную древовидную структуру, поэтому я ve ended up with the following struct`s:

    template<typename T>
    struct Node
    {
        T value;
        std::vector<Node<T>> kids;
        boost::optional<Node<T>> parent { boost::none };
    };

    template<typename T>
    struct Tree
    {
        std::vector<Node<T>> heads;
    };

Но когда я попытался использовать такие Tree/Node, как, например, значение в unordered_map, я получил ошибку компиляции (MSVC 17.0, C++ 14):

...\boost\include\boost/optional/detail/optional_aligned_storage.hpp(31): error C2027: use of undefined type "Node<std::shared_ptr<Action>>"

После некоторого гугления и запроса Chat-GPT было предложено заменить

boost::optional<Node<T>> parent { boost::none };

с

boost::optional<std::reference_wrapper<Node<T>>> parent { boost::none };

Это сработало. Однако я, честно говоря, понятия не имею, почему именно. Кто-нибудь может это объяснить?

Минимальный воспроизводимый пример на godbolt: нажмите;

boost::optional требует полного типа, и в этот момент Node не является полным. std::reference_wrapper сделайте его объектом, похожим на указатель, который не требует полного типа.
wohlstad 29.06.2024 13:02
Node<T>* parent = nullptr; может быть альтернативой.
Jarod42 29.06.2024 13:19

Часто для этого вы просто используете указатели. Обычно вы также можете использовать nullptr вместо optional (также рассмотрите std::optional вместо boost — я часто использую boost, но только с вещами, которых еще нет в C++). Кроме того, имейте в виду, что использование ссылок на другие узлы вместо реальных узлов означает, что вам придется позаботиться об очистке - я не знаю, как ваша структура должна работать, поэтому, возможно, здесь будет полезно std::unique_ptr, так как это также очистит родительский узел, как это сделал бы встроенный узел.

Christian Stieber 29.06.2024 14:13

Здесь не нужен boost::optional, используйте необработанный указатель.

Evg 29.06.2024 16:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кто-нибудь может это объяснить?

boost::optional требуется полный тип. Node еще не завершен, когда вы пытаетесь определить parent с его помощью (оно будет завершено после ; в конце определения структуры).
Причина boost::optional<T> требует полного типа в том, что он удерживает T внутри себя. В вашем случае для этого потребуется Node удерживать Node внутри себя, что невозможно.
Дополнительную информацию о полных и неполных типах можно увидеть здесь: Когда возникает ошибка неполного типа в C++

Использование std::reference_wrapper решает проблему, поскольку создает std::reference_wrapper<Node<T>> объекты, похожие на указатели. Такие объекты не требуют указателя полного типа (грубо говоря, потому, что все указатели одинаковы, независимо от того, на что они указывают).

Вместо boost::optional и std::reference_wrapper вы можете просто использовать необработанный указатель и получить:

Node<T> * parent { nullptr };

Вы можете использовать nullptr как эквивалент пустого boost::optional.

@Evg, хорошо сказано. Я добавил это в ответ.

wohlstad 30.06.2024 15:52

Не знал, что для boost::optional требуется полный тип. Спасибо!

Anton Grant 30.06.2024 17:46

Другие вопросы по теме