Могу ли я назначить / построить std :: вариантв / из стандартного варианта :: вариант? - PullRequest
0 голосов
/ 31 декабря 2018

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

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

#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 вариант не совсем то же самое животное).Я не смог найти отчет о дефекте или предложение, поэтому, возможно, мне не хватает какой-то причины "темного угла" C ++, почему это не разрешено.

1 Ответ

0 голосов
/ 31 декабря 2018

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

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

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

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

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

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

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);
...