Проблемы с использованием std :: option на std :: tuple - PullRequest
0 голосов
/ 15 октября 2018

Я бы хотел использовать std::variant для обработки типа варианта, но столкнулся с некоторыми проблемами.

#include <string>
#include <vector>
#include <tuple>
#include <variant>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;

void test_variant()
{
    using A = int;
    using B = double;
    using C = std::string;
    using var_t = std::variant<A, B, C>;

    using var_pair_t = std::tuple<var_t, var_t>;
    std::vector<var_pair_t> vec;

    for (var_pair_t const& var_pair : vec)
        std::visit(overloaded{
                    [](std::tuple<A, A> const& pair_A) {},
                    [](std::tuple<B, B> const& pair_B) {},
                    [](std::tuple<C, C> const& pair_C) {},
                    [](auto const& arg) {},
            }, var_pair);
}

На GCC: https://gcc.godbolt.org/z/p1ljQv
На VS2017 ошибка компилятора:

C2672: 'функция': не найдено соответствующей перегруженной функции
C2783: 'объявление': не удалось вывести аргумент шаблона для 'идентификатора'

Я хочу обработать парутого же типа.Что я делаю не так?Я предполагаю, что пары с разными типами будут соответствовать auto const& arg, поэтому все пары должны соответствовать правильно.

1 Ответ

0 голосов
/ 15 октября 2018

Это просто не то, как std::visit указано:

template <class Visitor, class... Variants>
constexpr /*see below*/ visit(Visitor&& vis, Variants&&... vars);

Требуется пакет параметров variant с.Это не займет tuple из них, хотя это очень похожие вещи.И когда вы visit несколько variant с, ваши вызовы функций вызываются с несколькими аргументами, а не tuple из них.

Чтобы использовать стандартный механизм, вы хотите:

std::visit(overloaded{
            [](A const&, A const&) {},                // <== unpack all of these
            [](B const&, B const&) {},
            [](C const&, C const&) {},
            [](auto const&, auto const&) {},
    }, std::get<0>(var_pair), std::get<1>(var_pair)); // <== unpack this too

Если вы предпочитаете работать в tuple s, вы можете написать свою собственную версию visit, которая распаковывает variant s и перепаковывает элементы:

template <typename F, typename Tuple>
decltype(auto) visit_tuple(F f, Tuple t) {
    return std::apply([=](auto... vs){          // <== unpack the variants
        return std::visit([=](auto... elems){
            return f(std::tuple(elems...));     // <== repack the alternatives
        }, vs...);
    }, t);
}

Правильная обработка и пересылка ссылокоставил как упражнение.

...