Here is a short c++14 version:
template<std::size_t...Is>
auto indexer( std::index_sequence<Is...> ) {
return [](auto && f) {
return f( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto indexer() {
return indexer( std::make_index_sequence<N>{} );
}
template<std::size_t N, class T>
auto except_nth( T&& t ) {
constexpr auto size = std::tuple_size< std::decay_t<T> >{};
static_assert( N < size, "No skipping past the end" );
auto before = indexer<N>();
auto after = indexer< size-N-1 > ();
return before( [&]( auto...As ) {
return after( [&]( auto...Bs ) {
return std::make_tuple( std::get<As>(std::forward<T>(t))..., std::get<N+1+Bs>(std::forward<T>(t))... );
} );
});
}
Live example.
This avoids depth-N template instantiation recursion of template instantiation "volume" N^2, which is hard to do in C++11 for this problem.
indexer
is a cute little helper that lets us expand counting parameter packs without having to write a new function.
indexer<N>()( [&]( auto...Is ) { /* code */ } )
gives us the integers 0
through N-1
in a pack Is...
within /* code */
.
We do this twice, once for the leading elements, once for the tailing. Then we wrap it all up in a single make_tuple
call.
Note that gcc in c++14 mode needs
return std::make_tuple( std::get<decltype(As){}>(std::forward<T>(t))..., std::get<N+1+decltype(Bs){}>(std::forward<T>(t))... );
as it won't let you call a member function with a non-constexpr object even if the function does not use this
. clang works fine, even in c++14. I think this was a standard ambiguity that was cleared up later.