std::optional имеет шаблонные конструкторы преобразования копирования и преобразования перемещения, которые позволяют создавать экземпляр std::optional<B> с экземпляром std::optional<A>, когда B можно построить из A .

К сожалению, похоже, что эти конструкторы не работают с boost::variant, у которого есть bool в пределах допустимых типов. Почему так?

Вы можете видеть, что ограничение применяется к std::optional, но не применяется к boost::optional в следующем креплении. Код также воспроизводится ниже.

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
    }
}
2
Dalzhim 12 Фев 2021 в 22:20

1 ответ

Лучший ответ

boost::variant<B, bool> утверждает, что может быть создан из std::optional<A>, потому что bool может быть построен из std::optional<A> (из-за оператор явного преобразования).

Из-за этого std::optional<boost::variant<B, bool>> попытается построить содержащийся объект непосредственно из std::optional<A> без разворачивания.

Но реализация boost::variant использует неявное преобразование внутри, и вы не можете неявно преобразовать optional в bool, отсюда и ошибка.

3
Enlico 12 Фев 2021 в 22:11