在任意索引上拆分 std::tuple

Split an std::tuple on an arbitrary index

我有一个 std::tuple,我想在任意编译时参数 N 处拆分它。我已经看到解决方案四处飘荡以获取 std::tuple 的头部和尾部,例如 here , here or here ,但这些无法解决我的问题,因为对我而言,这个常量(如 1)作为模板参数传递是一个运行时参数,它违背了 std::index_sequence 的目的。例如这样的东西,不起作用:

#include <iostream>
#include <tuple>
#include <utility>


template < typename T , typename... Ts >
auto head( std::tuple<T,Ts...> t )
{
   return  std::get<0>(t);
}

template <std::size_t... Ns , typename... Ts>
auto tail_impl( std::index_sequence<Ns...> , std::tuple<Ts...> t, std::size_t N)
{
   return  std::make_tuple( std::get<Ns + N>(t)... );
}

template < std::size_t N, typename... Ts>
auto tail( std::tuple<Ts...> t)
{
   return  tail_impl( std::make_index_sequence<sizeof...(Ts) - N>() , t, N);
}

int main()
{
   auto t = std::make_tuple( 2, 3.14 , 'c' , 5);
   std::cout << std::get<0>( tail<2>(t) ) << std::endl;
}

因此我的问题是:这可能吗?例如,如果我可以有一个从任意 N 开始的 std::index_sequence,这会更简单,但我找不到如何做到这一点。

你就在附近。

你的错误是将 N 作为参数从 tail() 传递给 tail_impl()

您应该将其作为模板参数传递

template < std::size_t N, typename... Ts>
auto tail( std::tuple<Ts...> t)
{
   // ..............VVV
   return  tail_impl<N>( std::make_index_sequence<sizeof...(Ts) - N>() , t);
}

tail_impl()变成

// .......VVVVVVVVVVVVVV
template <std::size_t N, std::size_t... Ns , typename... Ts>
auto tail_impl( std::index_sequence<Ns...> , std::tuple<Ts...> t)
{
   return  std::make_tuple( std::get<Ns + N>(t)... );
}

你的代码中的问题是,如果你将 N 作为普通函数参数传递,你不能在 std::get<Ns + N> 中使用它,因为 std::get() 的模板参数 (Ns + N,在你的情况下)必须是编译时已知的,但普通函数参数也可以是 运行 时间已知值。

This would be simpler if I could have an index_sequence starting from an arbitrary N for example but I couldn't find how to do that.

从任意N开始的std::index_sequence是可能的;也可以 std::index_sequence 数字无序。

问题是没有一个标准 std::make_index_sequence 相当于从 N.

创建一个 std::index_sequence

显然你可以创建它

template <std::size_t Shift, std::size_t ... Is>
constexpr std::index_sequence<Shift+Is...>
   misws_helper (std::index_sequence<Is...>);

template <std::size_t N, std::size_t Shift = 0u>
using make_index_sequence_with_shift
  = decltype(misws_helper<Shift>(std::make_index_sequence<N>{}));

// ...

using IS0 = std::index_sequence<3u, 4u, 5u, 6u, 7u>;
using IS1 = make_index_sequence_with_shift<5u, 3u>;

static_assert( std::is_same<IS0, IS1>::value, "!" );