【问题标题】:Problems with using std::variant on std::tuple在 std::tuple 上使用 std::variant 的问题
【发布时间】:2019-03-20 03:01:05
【问题描述】:

我想使用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&amp; arg,所以所有对都应该正确匹配。

【问题讨论】:

    标签: c++ c++17 variant


    【解决方案1】:

    std::visit 不是这样指定的:

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

    它需要一个variants 的参数包。它不需要tuple,即使它们非常相似。当你 visit 多个 variants 时,你的函数调用会使用多个参数 - 而不是其中一个 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
    

    如果您更喜欢在tuples 中工作,您可以编写自己的visit 版本,将variants 解包并重新打包元素:

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

    正确的引用处理和转发留作练习。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-25
      • 2019-06-15
      • 1970-01-01
      相关资源
      最近更新 更多