Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we use variadic template function to filter parameters of specific type, then pass the rest to another function?

for example

// we have a variadic function
void print(...);    

// I need such a function to filter parameters of specific type
template<typename... Args>
void print_filter(const Args&... args)
{
    // filter non-integral type
    print(integral args);
}

// my goal, all non-integral type can be ignored:
print_filter(1.0, 2, "abc", 3) == print(2, 3)

I have used up my knowledge to do that... can you help? or just to prove it's impossible, which also be very helpful. Thanks

like image 571
P.X Avatar asked Apr 20 '16 14:04

P.X


People also ask

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

Which of the following are valid reasons for using Variadic templates in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is a Variadic template C++?

A variadic template is a class or function template that supports an arbitrary number of arguments. This mechanism is especially useful to C++ library developers: You can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.

What is a parameter pack C++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.


1 Answers

A neat trick is to convert the arguments you want into a 1-element forwarding tuple, the arguments you don't want into an empty tuple, tuple_cat the results, then apply (C++17) the resulting tuple to the function you want to invoke:

template<typename... Args>
void print_filter(Args&&... args) {
    std::apply(
        [](auto&&... args) { return print(std::forward<decltype(args)>(args)...); },
        std::tuple_cat(
            std::get<std::is_integral<typename std::decay<Args>::type>::value ? 0 : 1>(
                std::make_tuple(
                    [](Args&& arg) { return std::tuple<Args&&>{std::forward<Args>(arg)}; },
                    [](Args&&) { return std::tuple<>{}; }))(
                std::forward<Args>(args))...));
}

Note that this employs another trick, which is to use get to conditionally apply one of two functions to an argument.

Example.

like image 174
ecatmur Avatar answered Sep 23 '22 15:09

ecatmur