Search code examples
c++templatesboostc++14

Fixing boost::optional undefined type error


I was trying to create a bidirectional tree-like structure, so Ive 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;
    };

But when I tried to use such Tree/Node as, for instance, value in unordered_map, I got compilation error (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>>"

After some googling and asking Chat-GPT, it was suggested to replace

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

with

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

That worked. However, I honestly have no idea why exactly. Can anyone explaing that?

Minimal reproducible example on godbolt: click;


Solution

  • Can anyone explaing that?

    boost::optional requires a complete type. Node is not yet complete when you attempt to define parent using it (it will be complete after ; at the end of the struct definition).
    The reason boost::optional<T> requires a complete type is that it holds T inside itself. In your case this would require Node to hold a Node inside itself which is impossible.
    You can see some more info about complete and incomplete types here: When does an Incomplete Type error occur in C++

    Using std::reference_wrapper solves the problem because it makes std::reference_wrapper<Node<T>> a pointer-like objects. Such objects do not require the pointee to the a complete type (roughly speaking it's because all pointers are similar, no matter what they point to).

    Intead of boost::optional and std::reference_wrapper you can simply use a raw pointer and have:

    Node<T> * parent { nullptr };
    

    You can use nullptr as an equivalent to an empty boost::optional.