c++ - 如何展平异构列表(又名......元组的元组)

标签 c++ tuples c++17 flatten perfect-forwarding

我正在尝试使用 C++17 折叠表达式和 C++14 索引技巧来展平由元组和非元组组成的任意输入。

预期的结果至少应该符合这些要求:

constexpr auto bare = 42;

constexpr auto single = std::tuple{bare};
constexpr auto nested_simple = std::tuple{single};

constexpr auto multiple = std::tuple{bare, bare};
constexpr auto nested_multiple = std::tuple{multiple};

constexpr auto multiply_nested = std::tuple{multiple, multiple};

static_assert(flatten(bare) == bare);
static_assert(flatten(single) == bare);
static_assert(flatten(nested_simple) == bare);

static_assert(flatten(multiple) == multiple);
static_assert(flatten(nested_multiple) == multiple);

static_assert(flatten(multiply_nested) == std::tuple{bare, bare, bare, bare});

除了最后一种情况,我有相对简单的代码来处理所有情况:

template<typename T>
constexpr decltype(auto) flatten(T&& t)
{
    return std::forward<T>(t);
}

template<typename T>
constexpr decltype(auto) flatten(std::tuple<T> t)
{
    return std::get<0>(t);
}

template<typename... Ts>
constexpr decltype(auto) flatten_multi(Ts&&... ts)
{
    return std::make_tuple(flatten(ts)...);
}

template<typename... Ts, std::size_t... Indices>
constexpr decltype(auto) flatten_impl(std::tuple<Ts...> ts, const std::index_sequence<Indices...>&)
{
    return flatten_multi(std::get<Indices>(ts)...);
}

template<typename... Ts>
constexpr decltype(auto) flatten(std::tuple<Ts...> ts)
{
    return flatten_impl(ts, std::make_index_sequence<sizeof...(Ts)>());
}

Live demo here .显然,它不能很好地处理多重嵌套项。

处理 multiply_nested 情况的更高级形式我还没有找到。我尝试应用 operator>> 来使用折叠表达式,但无法获得任何可编译的内容。我最后的尝试可以找到here .核心思想是在折叠表达式中使用 operator>> 将元素 2 乘 2 组合,每次展开前一个结果。

在我看来,我应该可以使用像 std::tuple_cat 这样的东西,但它对我大喊大叫,原因我无法完全理解。

所以我的问题是:我错过了什么?如何打开任意深度任意嵌套的类似元组的输入?

最佳答案

我向 SFINAE 建议存在 tuple

// Simple traits
template <typename T> struct is_tuple : std::false_type{};
template <typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type{};

// utility to ensure return type is a tuple
template<typename T>
constexpr decltype(auto) as_tuple(T t) { return std::make_tuple(t); }

template<typename ...Ts>
constexpr decltype(auto) as_tuple(std::tuple<Ts...> t) { return t; }

// Simple case
template<typename T>
constexpr decltype(auto) flatten(T t)
{
    return t;
}

// Possibly recursive tuple
template<typename T>
constexpr decltype(auto) flatten(std::tuple<T> t)
{
    return flatten(std::get<0>(t));
}

// No more recursion, (sizeof...Ts != 1) with above overload
template<typename ...Ts, std::enable_if_t<!(is_tuple<Ts>::value || ...), bool> = false>
constexpr decltype(auto) flatten(std::tuple<Ts...> t)
{
    return t;
}

// Handle recursion
template<typename ...Ts, std::enable_if_t<(is_tuple<Ts>::value || ...), bool> = false>
constexpr decltype(auto) flatten(std::tuple<Ts...> t)
{
    return std::apply([](auto...ts)
                      {
                          return flatten(std::tuple_cat(as_tuple(flatten(ts))...));
                      }, t);
}

Demo

关于c++ - 如何展平异构列表(又名......元组的元组),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54931352/

相关文章:

c++ - sscanf 变长字符串解析

python - 将元组列表映射到字典中

c# - 元组旨在解决什么需求?

c++ - GCC 9.1 返回 void& 作为显式析构函数调用的结果类型。这是一个错误吗?

c++ - 掩蔽结构名称

c++ - SFINAE : Derived class hide base class function depend on T

c++ - QCustomPlot链接器

c++ - 从 char 到 int 的转换做了一些奇怪的事情

C++ Nvidia Cg问题

python - 从Python中的元组列表创建vtkPolyData对象