在任意索引上拆分 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, "!" );
我有一个 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, "!" );