如何展平异构列表(又名...的元组) [英] How to flatten heterogeneous lists (aka tuples of tuples of ...)
问题描述
我正在尝试使用C ++ 17折叠表达式和C ++ 14索引来欺骗扁平化由元组和非元组组成的任意输入.
I am attempting to employ C++17 fold expressions and the C++14 indices trick to flatten an arbitrary input consisting of tuples and non-tuples.
预期结果至少应符合以下要求:
The expected result should at least conform to these requirements:
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});
除了最后一种情况,我有相对简单的代码来处理所有问题:
I have relatively simple code to handle all but the last case:
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. Obviously, it doesn't handle multiply nested items well.
用于处理我未找到的 multiply_nested
情况的更高级的表单.我尝试应用 operator>>
以便能够使用折叠表达式,但还无法获得可编译的任何内容.我的最后一次尝试可以在此处一个>.核心思想是每次折叠前一个结果时,在折叠表达式中使用 operator>>
组合元素2×2.
The more advanced form to handle the multiply_nested
case I haven't found. I tried applying operator>>
to be able to use fold expressions, but haven't been able to get anything that compiles. My last attempt can be found here. The core idea is to use operator>>
in a fold expression to combine elements 2 by 2, each time unwrapping the previous result.
在我看来,我应该可以使用 std :: tuple_cat
之类的东西,但是由于无法完全解密的原因,它大声地对我吼叫.
It seems to me I should be able to use something like std::tuple_cat
, but it shouted at me quite loudly for reasons I couldn't decipher completely.
所以我的问题是:我想念什么?如何解开任意深度嵌套的类似元组的输入?
So my question is this: what am I missing? How can I unwrap an arbitrarily deeply arbitrarily nested tuple-like input?
推荐答案
我建议在存在 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);
}
这篇关于如何展平异构列表(又名...的元组)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!