【发布时间】:2019-07-22 16:51:43
【问题描述】:
我正在尝试使用 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 之类的东西,但由于我无法完全破译的原因,它对我大喊大叫。
所以我的问题是:我错过了什么?如何解开任意深度任意嵌套的类元组输入?
【问题讨论】:
-
请注意,这个
constexpr auto nested_simple = std::tuple{single};并没有做你认为的那样。 -
@Barry 好点!一直以来,我都在想
make_tuple是否被类模板参数推导所取代。我猜不是。 -
澄清一下:
std::tuple<int&>应该被展平为std::tuple<int&>和std::tuple<std::tuple<int, double>&>应该被展平为std::tuple<std::tuple<int, double>&>是否正确(即,参考未被触及)? -
@Julius 在我看来,此刻,是的,引用应该保持不变。如果提供了参考作为输入,则应输出参考。
标签: c++ tuples c++17 flatten perfect-forwarding