我有以下结构,我想从index_sequence中删除最后一个参数:
template< std::size_t ... values>
struct index_sequence{};
// I need something like
template< typename IndexSequence>
struct pop_back;
template< std::size_t ... values >
struct pop_back< index_sequence< values... > >
{
typedef index_sequence< /** values except last one*/ > type;
};
如何实现这个pop_back结构?
我知道实现,只需要深度递归,我想要没有深度递归的瞬间.
我的实施:
template< std::size_t i, typename IndexSequence >
struct insert_head;
template< std::size_t i, std::size_t ...values>
struct insert_head< i, index_sequence<values...> >
{
typedef index_sequence< i, values... > type;
};
template< >
struct pop_back< index_sequence<> >
{
typedef index_sequence<> type; // no element will removed
};
template< std::size i > struct pop_back< index_sequence< i > >
{
typedef index_sequence<> type; // i - will removed
};
template< std::size_t i, std::size_t ...values>
struct pop_back< index_sequence<i,values...>>
{
typedef typename pop_back< index_sequence<values...> >::type tail;
typedef typename insert_head< i, tail>::type type;
};
Edit2:另一个有用的算法,选择第i个元素!
template< std::size ...i> struct index_sequence;
template< std::size_t index, typename IndexSeq> struct at;
template< std::size_t index, std::size_t ... values>
struct at< index, index_sequence<values...> >
{
static constexpr std::size_t get_value()noexcept
{
using list = std::size_t [];
return list{ values...}[index];
}
static constexpr std::size_t value = get_value();
}
// test
// -- 0 1 2 3 4
typedef index_sequence<2,4,6,8,10> even_t;
static_assert( at<2, even_t>::value == 6, "!");
最佳答案 再次使用
Xeo’s
O(logN) instantiation depth version of gen_seq,稍加修改:
#include <cstddef>
// using aliases for cleaner syntax
template<class T> using Invoke = typename T::type;
template<std::size_t...> struct seq{ using type = seq; };
template<class S1, class S2> struct concat;
template<std::size_t... I1, std::size_t... I2>
struct concat<seq<I1...>, seq<I2...>>
: seq<I1..., (sizeof...(I1)+I2)...>{};
template<class S1, class S2>
using Concat = Invoke<concat<S1, S2>>;
template<std::size_t N> struct gen_seq;
template<std::size_t N> using GenSeq = Invoke<gen_seq<N>>;
template<std::size_t N>
struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
template<> struct gen_seq<0> : seq<>{};
template<> struct gen_seq<1> : seq<0>{};
现在,通过朋友功能使用我以前的一个技巧& ADL:
#include <tuple>
#include <type_traits>
template<class T, std::size_t I>
struct type_index_pair
{
friend T my_declval(type_index_pair,
std::integral_constant<std::size_t, I>);
};
template<class, class>
struct pop_back_helper;
template<class... TT, std::size_t... Is>
struct pop_back_helper<std::tuple<TT...>, seq<Is...>>
{
struct base : type_index_pair<TT, Is>...
{};
template<std::size_t... Is2>
using join = std::tuple< decltype(my_declval(base{},
std::integral_constant<std::size_t, Is2>{}))... >;
};
template<class... TT, std::size_t... Is, std::size_t... Is2>
auto deduce(seq<Is...>, seq<Is2...>)
-> typename pop_back_helper<std::tuple<TT...>, seq<Is...>>
::template join<Is2...>
{ return {}; } // definition not required, actually
template<class... TT>
using pop_back = decltype(deduce<TT...>(gen_seq<sizeof...(TT)>{},
gen_seq<sizeof...(TT)-1>{}));
用法示例:
#include <iostream>
template<class T>
void pretty_print(T)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
pretty_print( pop_back<int, bool, char, double>{} );
pretty_print( pop_back<double, int, int>{} );
}
我对此并不特别满意,因为它需要两个序列加上ADL(需要资源且速度很慢,AFAIK).也许我会在接下来的几天里想出更好的东西.