Могу ли я назначить / создать std::variable<Ts...> для / из std::variable<Ts..., Ys...>?

Мне кажется, что назначение чего-то, что может быть яблоками или апельсинами, что-то, что может быть яблоками, апельсинами или клубникой, является четко определенным.

Почему тогда я не могу этого сделать?

#include <variant>

int main()
{
    std::variant<int> v1{42};
    std::variant<int, char> v2{v1}; // copy construction
    v2 = v1; // copy assignment
    v2 = std::move(v1); // move assignment
    std::variant<int, char> v3{std::move(v2)}; // move construction
}

Концептуально это кажется правильным. Даже Boost:: Вариант позволяет это (хотя STD и Boost вариант не совсем то же самое животное). Я не смог найти отчет о дефекте или предложение, поэтому, возможно, мне не хватает какой-то причины, почему это не разрешено.

1 ответ

Это просто не поддерживается в стандартной библиотеке по любой причине. std::variant был очень длинный, очень спорный процесс. Может быть, этот конкретный аспект просто не был в чьем-то списке?

Единственное возможное техническое беспокойство по поводу добавления такого конвертирующего конструктора и конвертирующего оператора присваивания - это странные патологические взаимодействия с текущим. Прямо сейчас, variant<Ts...> имеет конструктор, принимающий T&& который он пытается выбрать Ts за. Это может привести к конфликту, и вам придется ответить на вопрос, что вы хотите здесь произойти:

struct X { X(variant<int>); };

variant<int>    v = 42;
variant<int, X> w = v;

В настоящее время это действительно, и w держит X построен из v, Хотели бы вы, чтобы это изменилось и имело w держать int42?


Сейчас вам просто нужно сделать это вручную:

template <typename To, typename From>
To variant_cast(From&& from) {
    return std::visit(
        [](auto&& elem) { return To(std::forward<Elem>(elem)); },
        std::forward<From>(from));
}

Вы не получите такой приятный синтаксис (и вышеприведенная реализация не является SFINAE-дружественной), но он выполняет свою работу:

using V2 = variant<int, char>;
auto v2 = variant_cast<V2>(v1);
v2 = variant_cast<V2>(v1);
v2 = variant_cast<V2>(std::move(v1));

// at least this one is stil easy :-)
auto v3 = std::move(v2);
Другие вопросы по тегам