问题
I have following structure, I want remove last argument from 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;
};
How to implement this pop_back
structure?
I know implementation, only it requires deep recursion, I want without deep recursion instantination.
My implementation:
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: Another useful algo, select i-th element !!!
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, "!");
回答1:
Again, using Xeo's O(logN) instantiation depth version of gen_seq, slightly modified:
#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>{};
Now, using one of my former tricks via a friend function & 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>{}));
Usage example:
#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>{} );
}
I'm not particularly happy with it, as it requires two sequences plus the ADL (which requires resources and is slow, AFAIK). Maybe I'll be able to come up with something better in one of next days.
回答2:
there is solution my own question:
template< int ...i> struct seq{};
// GCC couldn't optimize sizeof..(i) ,
//see http://stackoverflow.com/questions/19783205/why-sizeof-t-so-slow-implement-c14-make-index-sequence-without-sizeof
//so I use direct variable `s` instead of it.
// i.e. s == number of variadic arguments in `I`.
template< int s, typename I, typename J > struct concate;
template< int s, int ...i, int ...j>
struct concate<s, seq<i...>, seq<j...> >
{
typedef seq<i..., (s + j)...> type;
};
template<int n> struct make_seq_impl;
template< int n> using make_seq = typename make_seq_impl<n>::type;
template<> struct make_seq_impl<0>{ typedef seq<> type;};
template<> struct make_seq_impl<1>{ typedef seq<0> type;};
template<int n> struct make_seq_impl: concate< n/2, make_seq<n/2>, make_seq<n-n/2>>{};
//----------------------------------------------------
// Our solution:
template< std::size_t ...> struct index_sequence{};
template< typename IndexSequence> struct pop_back;
// empty index_sequence
template<>struct pop_back< index_sequence<> >
{
typedef index_sequence<> type;
};
template< std::size_t ...i>
struct pop_back< index_sequence<i...> >
{
static constexpr std::size_t size = sizeof...(i);
static constexpr std::size_t values[] = {i...};
template< typename sq> struct apply;
template< int ...j> struct apply< seq<j...> >
{
typedef index_sequence< values[j]... > type;
};
typedef typename apply< make_seq< size - 1 > >::type type;
};
// test
int main()
{
typedef index_sequence< 2, 4, 6, 8, 10> ievens;
typedef pop_back< ievens>::type jevens;
static_assert( std::is_same< jevens, index_sequence<2,4,6,8> >::value ,"!");
}
来源:https://stackoverflow.com/questions/20035374/how-to-remove-last-argument-of-variadic-template