13

I'm searching for a way to remove (let's say for now all occurences of) a type from a template parameter pack. The end result would be a struct that looked like this :

template<typename T, typename...Ts>
struct RemoveT
{
    using type = /* a new type out of Ts that does not contain T */
}

Let's say that the marginal case RemoveT<int, int> would be handled by returning void (not handled in the code that follows). My initial design looks like this:

// --------------------------------------------------------------
// 1. A "way" of typedefing variadic number of types ------------
template<typename...Ts>
struct pack { 
    using type = Ts; 
};
// --------------------------------------------------------------

// --------------------------------------------------------------
template<typename T, typename...Ts> struct RemoveT;

template<typename T, typename T1, typename...Ts>
struct RemoveT {
    using type = typename pack<T1, typename RemoveT<T, Ts...>::type>::type;
};

template<typename T, typename T1>
struct RemoveT<T, T1> { 
    using type = T1; 
};

template<typename T, typename...Ts>
struct RemoveT<T, T, Ts...> {
    using type = typename RemoveT<Ts...>::type;
};
// --------------------------------------------------------------

Now I can't even begin to test this code because the pack structure is not valid C++

Reiteration

Just in case this is helpfull for an answer, some other thoughs on solving it

  • One could argue that pack is not even useful at all. We could instead move around the RemoveT structure, creating a new RemoveT that only contains the types needed. The problem then transforms in extracting the types out of the struct
  • We could create type pairs that mimic the behaviour of typelists and take a more recursive approach on this.

Bottom Line

For variadic types Ts and a type T: Can I create Us out of Ts ommiting T ?

Community
  • 1
  • 1
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • While i'm off in grey-matter thinking about this, I'm curious what i would be used for. I.e. What is an example application? – WhozCraig May 25 '14 at 13:28
  • @WhozCraig Good point. To quote a great programmer "If I told you, I'd have to kill you or hire you" :P ... and curiosity ofcourse – Nikos Athanasiou May 25 '14 at 13:40
  • You're right that you can't have `struct pack` as you have outlined here. But you can use `std::tuple` for example: `typedef std::tuple type;` which may be a quick way to get what you need there. – John Zwinck May 25 '14 at 13:51
  • This seems very broad. Are you sure you're not looking for a message board or chatroom of some description? – Lightness Races in Orbit May 25 '14 at 16:46
  • @LightnessRacesinOrbit Please point one out, I tried discussing this in the lounge and all I got was a downvote. – Nikos Athanasiou May 25 '14 at 17:02
  • @NikosAthanasiou: I don't know where people go on the internet to work this stuff out. IRC used to be pretty good for it. – Lightness Races in Orbit May 25 '14 at 17:16
  • I downvoted you because you dumped it. – Puppy May 25 '14 at 17:59
  • 1
    @DeadMG Didn't mention your name man (wasn't gona either). I have no direct complains, I was just replying to Lighness. It's perfectly fine to downvote anything you regard it's worth downvoting, I don't need to know the reasons. – Nikos Athanasiou May 25 '14 at 18:09

3 Answers3

12

The following provides a non-recursive and direct way to remove T from Ts... and, like Jarod42's solutions, yields a std::tuple<Us...> but without the need to use typename ...::type:

#include <tuple>
#include <type_traits>

template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));

template<typename T, typename...Ts>
using remove_t = tuple_cat_t<
    typename std::conditional<
        std::is_same<T, Ts>::value,
        std::tuple<>,
        std::tuple<Ts>
    >::type...
>;


int main()
{
    static_assert(std::is_same<
        remove_t<int, int, char, int, float, int>,
        std::tuple<char, float>
    >::value, "Oops");
}

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
8

Following may help:

namespace detail
{
    template <typename T, typename Tuple, typename Res = std::tuple<>>
    struct removeT_helper;


    template<typename T, typename Res>
    struct removeT_helper<T, std::tuple<>, Res>
    {
        using type = Res;
    };

    template<typename T, typename... Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes...>>
    {};

    template<typename T, typename T1, typename ...Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T1, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes..., T1>>
    {};

}

template <typename T, typename...Ts> struct RemoveT
{
    using type = typename detail::removeT_helper<T, std::tuple<Ts...>>::type;
};

static_assert(std::is_same<std::tuple<char, float>,
                        typename RemoveT<int, int, char, int, float, int>::type>::value, "");
Jarod42
  • 203,559
  • 14
  • 181
  • 302
3

First, move all the specific template names out into a list. There might be a way of specifying a template name, and a list of parameters, giving that template with the parameters, but I haven't been able to figure it out:

template <typename...TArgs> struct TypeList
{
    typedef std::tuple<TArgs...> tuple_type;
    // whatever other types you need
};

Next, define addition:

template<typename T, typename TList> struct AddT;

template<typename T, typename ... TArgs>
struct AddT< T, TypeList<TArgs...> >
{
    typedef TypeList<T, TArgs... > type;
};

Then, define removal:

template<typename R, typename ... TArgs> struct RemoveT;

template<typename R>
struct RemoveT<R>
{
    typedef TypeList<> type;
};

template<typename R, typename T, typename ...TArgs>
struct RemoveT<R, T, TArgs...>
{
    typedef typename std::conditional
        < std::is_same<R, T>::value
        , typename RemoveT<R, TArgs...>::type
        , typename AddT<T, typename RemoveT<R, TArgs...>::type>::type
        >::type type;
};

Finally, test:

int result = 0;
result = std::is_same
    < std::tuple<long,double>
    , RemoveT<int, int, long, int, double, int>::type::tuple_type
    >::value;
assert ( result );
KevinZ
  • 3,036
  • 1
  • 18
  • 26