Why isn't std::optional<boost::variant<A, bool>> successfully constructed from `std::optional<A>`?

Viewed 102

std::optional has copy conversion and move conversion templated constructors that make it possible to construct an instance of std::optional<B> with an instance of std::optional<A> when B is constructible from A.

Unfortunately, it seems that those constructors do not work with a boost::variant that has bool within the allowable types. Why is that the case?

You can see that the limitation applies to std::optional but does not apply to boost::optional in the following godbolt. Code is also reproduced below.

https://gcc.godbolt.org/z/PKTEET

#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <optional>

struct A
{};

struct B
{
    B(A) {}
};

void f() {
    boost::optional<A> boptA;
    boost::optional<B> boptB{boptA};
    std::optional<A> soptA;
    std::optional<B> soptB{soptA};

    {
        boost::optional<boost::variant<B>> vB;
        vB = boptA; // 1. success
    }

    {
        boost::optional<boost::variant<B, bool>> vB;
        vB = boptA; // 2. success
    }

    {
        std::optional<boost::variant<B>> vB;
        vB = soptA; // 3. success that compares with #1
    }

    {
        std::optional<boost::variant<B, bool>> vB;
        vB = soptA; // 4. compilation error that should have compared with #2
    }
}
1 Answers

boost::variant<B, bool> claims to be constructible from std::optional<A>, because bool is constructible from std::optional<A> (due to the explicit conversion operator).

Because of that, std::optional<boost::variant<B, bool>> will try to construct the contained object directly from std::optional<A> without unwrapping.

But boost::variant's implementation uses an implicit conversion internally, and you can't implicitly convert an optional to bool, hence the error.

Related