c++templatesc++11variadic-templatestemplate-meta-programming

How can a type be removed from a template parameter pack?


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

Bottom Line

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


Solution

  • 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