4

Is there a way to:

1) remove item at index:

// Removes item at index N, e.g. Remove<2, a, b, c, d> results in <a, b, d>
template<std::size_t N, typename ...Args>
struct Remove {
    // ???
};

2) replace item at index:

// Replaces item at index N with T, e.g. Replace<2, x, a, b, c, d> results in <a, b, x, d>
template<std::size_t N, typename T, typename ...Args>
struct Replace {
    // ???
};

3) replace items in range

// Replaces items in range [N1, N2] with T, e.g. ReplaceRange<2, 3, x, a, b, c, d> results in <a, b, x>
template<std::size_t N1, std::size_t N2, typename T, typename ...Args>
struct ReplaceRange {
    // ???
};

I want it to be used like that

class is_true {
public:
    bool operator()() const { return true; }
};


class is_false {
public:
    bool operator()() const { return false; }
};

class And {
};

class Or {
};

Filter f<is_true, And, is_true, Or, is_false>();

Now, I want to fold this to:

< FilterOr < FilterAnd <is_true, is_true>, is_false > >

Where

template<typename Lhs, typename Rhs>
class FilterAnd {
public:
    bool operator()() const { return Lhs() && Rhs(); }
};

template<typename Lhs, typename Rhs>
class FilterOr {
public:
    bool operator()() const { return Lhs() || Rhs(); }
};

So, I'm trying to do the following:

class Filter {
public:
    template <typename ...Args>
    void apply() {
        holder_ = FilterHolder<typename FoldOperator<Or, FilterOr, typename FoldOperator<And, FilterAnd, Args...>::type >::type >();
    }
}

FoldOperator basically removes operator arguments, and replaces operator with Filter class, e.g. for arguments <is_true, And, is_true>, I want to remove arguments (is_true) and replace operator (And) with Filter: FilterAnd<is_true, is_true> where arguments are the same as was removed from the list. So, I need replace/remove templates to perform that.

Thanks in advance.

maverik
  • 5,508
  • 3
  • 35
  • 55
  • 3
    Can you show how you'd implement an `Identity` function, so that we know what output format you expect? That's not clear from your question. – Angew is no longer proud of SO Jan 08 '16 at 15:38
  • Possible duplicate of [Insert/remove type into variadic template list (parameter pack)](http://stackoverflow.com/questions/28434651/insert-remove-type-into-variadic-template-list-parameter-pack) – AndyG Jan 08 '16 at 15:43
  • @Angew I don't quiet understand what did you mean. I want this to be like `template<...> struct Replace { typedef ... type; }`. – maverik Jan 08 '16 at 15:45
  • @maverik And that is exactly my question. Variadic template parameters/arguments exist only in a template declaration/instantiation, they are not a first-class object of the language. What you you put as `...` in case the functor was `Identity`, i.e. was supposed to leave the arguments intact? We cannot give a solution modifying something if we don't know what output format you want. – Angew is no longer proud of SO Jan 08 '16 at 15:48
  • @AndyG: I can't use C++14 and I don't want to use `std::tuple` if possible, because then I will end up rewriting all the code with tuples or I will need `LLONG_MAX` more lines of code to expand `std::tuple` to variadic list (like here: http://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments) – maverik Jan 08 '16 at 15:48
  • @maverik Please [edit] a suitably formatted example into the question. – Angew is no longer proud of SO Jan 08 '16 at 15:55

1 Answers1

9

This is way easier in C++14 with std::index_sequence, so I've used that. There are a bunch of implementations you can find of this online.

I use std::tuple to marshal everything around.

For Replace, I used std::conditional to choose either T or the correct tuple element for each type index.

For Remove, I take the decltype of tuple_catting either an empty tuple or tuple containing the correct tuple element for a non-removed type index.

namespace detail{
template<std::size_t N, typename T, typename Tuple, std::size_t... Idx>
auto replace (std::index_sequence<Idx...>) ->
    std::tuple<std::conditional_t<N == Idx, 
                                  T, 
                                  std::tuple_element_t<N, Tuple>>...>;

template<std::size_t N, typename Tuple, std::size_t... Idx>
auto remove (std::index_sequence<Idx...>) ->
    decltype(std::tuple_cat(
      std::declval<
        std::conditional_t<(N == Idx), 
                           std::tuple<>, 
                           std::tuple<std::tuple_element_t<Idx, Tuple>>
      >
    >()...
    ));
}

template <std::size_t N, typename T, typename... Args>
using Replace = decltype(detail::replace<N,T,std::tuple<Args...>>
                         (std::index_sequence_for<Args...>{}));

template <std::size_t N, typename... Args>
using Remove = decltype(detail::remove<N,std::tuple<Args...>>
                        (std::index_sequence_for<Args...>{})); 

ReplaceRange is left as an exercise to the reader.

Live Demo

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • Thanks, but I can't use C++14. Any idea how to port that to C++11? – maverik Jan 08 '16 at 16:04
  • 1
    Search online for an implementation of `std::integer_sequence` (I'm sure there are some on SO) and use `typename std::trait::type` instead of `std::trait_t`. – TartanLlama Jan 08 '16 at 18:05