Search code examples
c++variadic-templates

Invoking a member function with variadic template parameters that are not part of the function's arguments


Most of the questions I have found revolve around non-member functions where the variadic template parameters are also found in the function's arguments.

In my case, I am in a situation where I would like to filter the types coming into one of the variadic member functions and pass the filtered types to another variadic member function:

#include <tuple>
#include <type_traits>

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

// how the filtering of the types happen is not relevant
template<typename T, typename...Ts>
using remove_t = tuple_cat_t<
    typename std::is_empty_v<T>,
        std::tuple<>,
        std::tuple<Ts>
    >::type...
>;

struct Foo
{
    template <typename... T_Tags>
    void Bar(float arg)
    {
        // I would like to call DoBar() with a filtered set of T_Tags
        // where type filtering is done with something similar to what is outlined
        // here: https://stackoverflow.com/a/23863962/368599
        using filtered_args = std::remove_t<T_Tags...>;

        // not sure of the syntax here or if this is even possible
        std::invoke(&Foo::DoBar<???filtered_args???>, std::tuple_cat(std::make_tuple(this), std::make_tuple(arg)));
    }

    template <typename... T_FilteredTags>
    void DoBar(float arg)
    {
        // Do something with T_FilteredTags types
    }
};

Solution

  • You can use template lambda to expand the filtered types and specify them to DoBar explicitly

    struct Foo
    {
        template <typename First_Tag, typename... T_Tags>
        void Bar(float arg)
        {
            using filtered_args = remove_t<First_Tag, T_Tags...>;
    
            [&]<typename... T_FilteredTags>(std::tuple<T_FilteredTags...>*) { 
              std::invoke(&Foo::DoBar<T_FilteredTags...>, this, arg);
            } (static_cast<filtered_args*>(nullptr));
        }
    
        template<typename... T_FilteredTags>
        void DoBar(float arg)
        {
          // Do something with T_FilteredTags types
        }
    };
    

    Noted that there is no need to use tuple to concatenate this and arg, just pass them to std::invoke directly.

    Demo