Insert / remove a type in the list of variation patterns (package of parameters)

What is the best way to implement insertion and deletion indexing in a list of variational pattern types (parameter package)?

Required Code / Behavior:

template<typename...> struct List { /* ... */ }; static_assert(is_same < List<int, char, float>::Insert<int, 0>, List<int, int, char, float> >()); static_assert(is_same < List<int, char, float>::Insert<int, 2>, List<int, char, int, float> >()); static_assert(is_same < List<int, char, float>::Remove<0>, List<char, float> >()); static_assert(is_same < List<int, char, float>::Remove<1>, List<int, float> >()); 

I tried an implementation based on returning arguments to an initially empty list, but it was very difficult to read / maintain. The options were similar to this:

 template<typename T, int I, int ITarget, typename TResult> struct InsertImpl; 

I constantly increment I until it becomes equal to ITarget , canceling existing types in TResult , which is List<...> . When I equals ITarget , I also return T to TResult .

Deleting a type had a similar implementation - instead of going back twice when the indices were equal, I just skipped the type.

My cumbersome solution will implement and remove in terms of pushing and popping. I believe that it would be more elegant to bring to the front equal to Insert<0> and click on the back equal to Insert<size> . The same goes for popping up front and back.

Is there a better way to do this? Can C ++ 14 help?

+5
source share
3 answers

Since you mentioned C ++ 14, another std::index_sequence is used here. The main reason that I think is worth mentioning is the use of constexpr display constexpr to place types at their positions in the resulting List . This makes the implementation relatively simple.

 #include <cstddef> #include <tuple> #include <utility> template<typename...> struct List; constexpr std::size_t map_ins(std::size_t i, std::size_t from, std::size_t to) { return i < to ? i : i == to ? from : i - 1; } template<typename, typename, std::size_t, typename...> struct ins_hlp; template<std::size_t... Is, typename U, std::size_t N, typename... Ts> struct ins_hlp<std::index_sequence<Is...>, U, N, Ts...> { static_assert(N <= sizeof...(Ts), "Insert index out of range"); using type = List<std::tuple_element_t<map_ins(Is, sizeof...(Ts), N), std::tuple<Ts..., U>>...>; }; constexpr std::size_t map_rem(std::size_t i, std::size_t idx) { return i < idx ? i : i + 1; } template<typename, std::size_t, typename...> struct rem_hlp_2; template<std::size_t... Is, std::size_t N, typename... Ts> struct rem_hlp_2<std::index_sequence<Is...>, N, Ts...> { using type = List<std::tuple_element_t<map_rem(Is, N), std::tuple<Ts...>>...>; }; template<std::size_t N, typename... Ts> struct rem_hlp { static_assert(N < sizeof...(Ts), "Remove index out of range"); using type = typename rem_hlp_2<std::make_index_sequence<sizeof...(Ts) - 1>, N, Ts...>::type; }; template<typename... Ts> struct List { template<typename U, std::size_t N> using Insert = typename ins_hlp<std::make_index_sequence<sizeof...(Ts) + 1>, U, N, Ts...>::type; template<std::size_t N> using Remove = typename rem_hlp<N, Ts...>::type; }; 

Sorry for the long lines, but I have not found another meaningful way to format these argument lists.

The only reason for having an additional helper for Remove is border checking; if this is not required, Remove can use the same template as Insert .

+1
source

Not sure if there is a β€œbetter” way, but this is a non-recursive way:

 #include <utility> #include <type_traits> #include <tuple> template<typename...Ts> struct List; template<typename T> struct ListFromTupleImpl; template<typename...Ts> struct ListFromTupleImpl<std::tuple<Ts...>> { using type = List<Ts...>; }; template<typename T> using ListFromTuple = typename ListFromTupleImpl<T>::type; template<typename...Ts> using TupleCat = decltype(std::tuple_cat(std::declval<Ts>()...)); template<typename...Ts> using ListFromTupleCat = ListFromTuple<TupleCat<Ts...>>; template<unsigned P,typename T,typename I> struct RemoveFromListImpl; template<unsigned P,typename...Ts,std::size_t...Is> struct RemoveFromListImpl<P,List<Ts...>,std::index_sequence<Is...>> { using type = ListFromTupleCat< std::conditional_t<(Is==P),std::tuple<>,std::tuple<Ts>>...>; }; // All elements < P template<unsigned P,typename T,typename I> struct HeadImpl; template<unsigned P,typename...Ts,std::size_t...Is> struct HeadImpl<P,List<Ts...>,std::index_sequence<Is...>> { using type = TupleCat< std::conditional_t<(Is>=P),std::tuple<>,std::tuple<Ts>>...>; }; // All elements >= P template<unsigned P,typename T,typename I> struct TailImpl; template<unsigned P,typename...Ts,std::size_t...Is> struct TailImpl<P,List<Ts...>,std::index_sequence<Is...>> { using type = TupleCat< std::conditional_t<(Is<P),std::tuple<>,std::tuple<Ts>>...>; }; template<typename N,unsigned P,typename T,typename I> struct InsertIntoListImpl { using head = typename HeadImpl<P,T,I>::type; using tail = typename TailImpl<P,T,I>::type; using type = ListFromTupleCat<head,std::tuple<N>,tail>; }; template<typename...Ts> struct List { /* ... */ template<std::size_t P> using Remove = typename RemoveFromListImpl<P,List<Ts...>, std::index_sequence_for<Ts...>>::type; template<typename N,std::size_t P> using Insert = typename InsertIntoListImpl<N,P,List<Ts...>, std::index_sequence_for<Ts...>>::type; }; static_assert(std::is_same < List<int, char, float>::Remove<0>, List<char, float> >(), ""); static_assert(std::is_same < List<int, char, float>::Remove<1>, List<int, float> >(), ""); static_assert(std::is_same < List<int, char, float>::Insert<int, 0>, List<int, int, char, float> >(), ""); static_assert(std::is_same < List<int, char, float>::Insert<int, 2>, List<int, char, int, float> >(), ""); int main(){} 

Living example

+3
source

Using Eric Nibler Tiny Metaprogram Library ( DEMO ):

 template <std::size_t N, typename List> using take_c = meta::reverse< meta::drop_c< meta::size<List>::value - N, meta::reverse<List> >>; template <typename...Ts> struct List { using mlist = meta::list<Ts...>; template <typename T, std::size_t I> using Insert = meta::apply_list< meta::quote<::List>, meta::concat< take_c<I, mlist>, meta::list<T>, meta::drop_c<I, mlist> >>; template <std::size_t I> using Remove = meta::apply_list< meta::quote<::List>, meta::concat< take_c<I, mlist>, meta::drop_c<I + 1, mlist> >>; }; 
+1
source

Source: https://habr.com/ru/post/1213066/


All Articles