How to Call a Function on All Variadic Template Args

How to call a function on all variadic template args?

C++17 fold expression

(f(args), ...);

If you call something that might return an object with overloaded comma operator use:

((void)f(args), ...);

Pre-C++17 solution

The typical approach here is to use a dumb list-initializer and do the expansion inside it:

{ print(Args)... }

Order of evaluation is guaranteed left-to-right in curly initialisers.

But print returns void so we need to work around that. Let's make it an int then.

{ (print(Args), 0)... }

This won't work as a statement directly, though. We need to give it a type.

using expand_type = int[];
expand_type{ (print(Args), 0)... };

This works as long as there is always one element in the Args pack. Zero-sized arrays are not valid, but we can work around that by making it always have at least one element.

expand_type{ 0, (print(Args), 0)... };

We can make this pattern reusable with a macro.

namespace so {
using expand_type = int[];
}

#define SO_EXPAND_SIDE_EFFECTS(PATTERN) ::so::expand_type{ 0, ((PATTERN), 0)... }

// usage
SO_EXPAND_SIDE_EFFECTS(print(Args));

However, making this reusable requires a bit more attention to some details. We don't want overloaded comma operators to be used here. Comma cannot be overloaded with one of the arguments void, so let's take advantage of that.

#define SO_EXPAND_SIDE_EFFECTS(PATTERN) \
::so::expand_type{ 0, ((PATTERN), void(), 0)... }

If you are paranoid afraid of the compiler allocating large arrays of zeros for naught, you can use some other type that can be list-initialised like that but stores nothing.

namespace so {
struct expand_type {
template <typename... T>
expand_type(T&&...) {}
};
}

Calling a function for each variadic template argument and an array

You could refactor or wrap f to return a new X instead of having it passed, since this would play pack expansion into the hand and make the function really concise:

template<class T>
X fw(T const& t){ X x; f(x, t); return x; }

template<class... Args>
void h(Args... args){
X xs[] = { fw(args)... };
g(xs, sizeof...(Args));
}

Live example.

And if you could change g to just accept an std::initializer_list, it would get even more concise:

template<class... Args>
void h(Args... args){
g({f(args)...});
}

Live example. Or (maybe better), you could also provide just a wrapper g that forwards to the real g:

void g(X const*, unsigned){}

void g(std::initializer_list<X> const& xs){ g(xs.begin(), xs.size()); }

template<class... Args>
void h(Args... args){
g({f(args)...});
}

Live example.

Edit: Another option is using a temporary array:

template<class T>
using Alias = T;

template<class T>
T& as_lvalue(T&& v){ return v; }

template<class... Args>
void h(Args... args){
g(as_lvalue(Alias<X[]>{f(args)...}), sizeof...(Args));
}

Live example. Note that the as_lvalue function is dangerous, the array still only lives until the end of the full expression (in this case g), so be cautious when using it. The Alias is needed since just X[]{ ... } is not allowed due to the language grammar.

If all of that's not possible, you'll need recursion to access all elements of the args pack.

#include <tuple>

template<unsigned> struct uint_{}; // compile-time integer for "iteration"

template<unsigned N, class Tuple>
void h_helper(X (&)[N], Tuple const&, uint_<N>){}

template<unsigned N, class Tuple, unsigned I = 0>
void h_helper(X (&xs)[N], Tuple const& args, uint_<I> = {}){
f(xs[I], std::get<I>(args));
h_helper(xs, args, uint_<I+1>());
}

template<typename... Args>
void h(Args... args)
{
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];

h_helper(xs, std::tie(args...));

g(xs, nargs);
}

Live example.

Edit: Inspired by ecatmur's comment, I employed the indices trick to make it work with just pack expansion and with f and g as-is, without altering them.

template<unsigned... Indices>
struct indices{
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices{
using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0>{
using type = indices<>;
};
template<unsigned N>
using IndicesFor = typename build_indices<N>::type;

template<unsigned N, unsigned... Is, class... Args>
void f_them_all(X (&xs)[N], indices<Is...>, Args... args){
int unused[] = {(f(xs[Is], args), 1)...};
(void)unused;
}

template<class... Args>
void h(Args... args){
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
f_them_all(xs, IndicesFor<nargs>(), args...);
g(xs, nargs);
}

Live example.

C++: How call a function with type parameter on variadic template arguments?

First of all, you forgot the

#include <tuple>

And the syntax you're probably looking for is:

return std::make_tuple(get<Ts>(stream)...);

Calling a variadic template function with a member function

One way is to modify the definition of your test() member function like so:

class Tester { 
public:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
int simple(int i) { return i; }
};

We can then pass a member function pointer to test(), with the instance on which the method should be called as the second argument, and then the function arguments themselves:

int main()
{
Tester t;
std::cout << t.test(&Tester::simple, t, 3);
}

The reason this works is because std::invoke has a special overload for pointers-to-members, such that

std::invoke(ptr-to-member, instance, args...);

is called as

(instance.*ptr-to-member)(args...);

which is exactly what we want in this case.

Call a variadic template functor in a variadic template parameter pack if it satisfies a condition

In C++17, this is easily solvable using fold expressions.

#include <functional>
#include <string>

template <typename Result, typename... Arguments>
class Functor
{
public:
using FunctionType = std::function<Result(Arguments...)>;
Result operator() (const Arguments&... args) {
return this->Function(arguments...);
}
std::string GetName() {
return this->Name;
}
Functor(const std::string& name, const FunctionType& function)
: Name(name), Function(function) { }

private:
std::string Name;
FunctionType Function;
};

template <typename... Functors>
void ForEachFunctor(const Functors&... functors)
{
((functors.getName() == "f" && functors()), ...);
}

Here, we exploit the short-circuiting of the && operator. Only if the condition functors.getName() == "f" is true, will the right hand side of the operator be evaluated.

A slightly less hacky approach uses a separate function:

template <typename Functor>
void InvokeIfNamedF(const Functor &functor) {
if (functor.GetName() == "f")
functor();
}

template <typename... Functors>
void ForEachFunctor(const Functors&... functors)
{
(InvokeIfNamedF(functors), ...);
}

The elements of the parameter pack are combined using the comma-operator. However, in this example, we are invoking each functor with no parameters. If all functors have distinct signatures then passing them as one pack and invoking them conditionally all at once is probably not possible.

C++11 variadic templates calling a function inside a class

I guess you're a bit mixing the variadic template part with a bit of design-flaw

Let's start.

Preamble: the correct way to deal with variadic templates is to use rvalue-reference and std::forward to achieve perfect forwarding.

1) The easy way: you don't need class at all

you're actually not referring to any member so a class bring only complexity. It's better to refer to a free function for these cases

#include <functional>
#include <iostream>

double finder(double a, double b = 0) {
return a + b;
};

template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};

int main () {
std::cout << var_finder(0.1, finder, 2, 0) << std::endl;

return 0;
}

Demo 1

your function accept 2 parameters so you have to pass zero as second argument.

2) Using a class

The problem with your attempt is you want to call c_test.var_finder with a function of c_test itself. Now you have to figure what kind of design you want. You can make 2 assumption. First is "I want anyway a finder function inside my class", then you have to make it static because it really does not use class member so you don't need an instance of c_test, right? so using a free function or a static member function leaves the var_finder implementation and you just have to call it this way

#include <functional>
#include <iostream>

class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
};


template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
};

int main () {
c_test test;

std::cout << test.var_finder(0.1, &c_test::finder, 2, 0) << std::endl;

return 0;
}

Demo 2

second assumption you can do is "nope, I want any function member to be called with var_finder regardless where it comes from". I strongly discourage this approach because is carving a solution from a bad design, so I suggest to rethink your design to fall to solution 1 or 2.

3) Bonus: a nice design

You can add a non-variadic function and delegate the usage to the use of a lambda, which allow you to use a member function inside it without defining a variadic template to deal with that (and it is the common implementation for the std library functions).

#include <functional>
#include <iostream>

double finder(double a, double b = 0) {
return a + b;
};

template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};

template<typename Func, typename... Args>
double var_finder(double c, Func&& f) {
return c * std::forward<Func>(f)();
};

class c_test
{
public:
double finder(double a, double b = 0) {
return a + b;
};
};

int main () {
double a = 2.0;
double b = 0.0;

// use as usual
std::cout << var_finder(0.1, finder, a, b) << std::endl;

// use with lambda
std::cout << var_finder(0.1, [a,b](){ return a+b; }) << std::endl;

// lambda with member argument, less gruesome than a variadic template calling a member function
c_test c;
std::cout << var_finder(0.1, [a,b, &c](){ return c.finder(a,b); }) << std::endl;

return 0;
}

Bonus Demo

Apply function to all elements of parameter pack from a variadic function

What I would like to do is to simply have printall apply print to
each element of the pack items. How can I get that done?

Option - 1

As user @liliscent and user @max66 suggested in the comments,
in C++11/ C++14 you can use the following hacky-way which act act like fold expressions in C++17.

SEE HERE

#include <iostream>

template <typename type> void print(const type& item)
{
std::cout << item << '\n';
}

template <typename... types>
void printall (const types&... items)
{
using dummy = int[];
(void)dummy { 0, (print(items), 0)... };
}

Option - 2

If the above does not look like good enough, provide a classical variadic templates overload as a wrapper/ helper between your printall() and print() functions, so that each template function arguments can be accessed in print().

SEE HERE

#include <iostream>

template <typename Type> void print(const Type& item)
{
std::cout << item << '\n'; // print each argument
}

namespace helper
{
void printall() {} // nontemplate overload for last call(i.e, no arguments call)

template<typename FirstArg, typename... Types>
void printall(const FirstArg& firstItem, Types&&... items)
{
::print(firstItem); // call print() for each argument
helper::printall(std::forward<Types>(items)...);// calls the same wrapper::printalll()
}
}

template <typename... Types> void printall(const Types& ... items)
{
helper::printall(items...); // calls the wrapper::printall()
}

Option - 3

However, if you have access to the C++17, just use fold expressions. That provides a clean(non-hacky) and less amount of code.

SEE HERE

template <typename type> void print(const type& item)
{
std::cout << item << '\n';
}

template <typename... types> void printall(const types&... items)
{
(print(items),...);
}

How to call variadic template function with defined first parameter through std::apply?

To use apply with extra arguments than tuple, you might capture it in the functor:

std::apply([&](auto&... args){ ValuesFromValuesVariant(params, args...); }, arguments);

or concat extra parameter to the tuple:

std::apply(&ValuesFromValuesVariant, std::tuple_cat(std::tie(params), arguments));

pass multiple arguments to another function using template variadic function

It seems to me that the Max Langhof's solution is simple and elegant.

Unfortunately it uses template folding that is available only starting from C++17.

I propose a C++11/C++14 version that, instead template folding, uses the old trick of the initialization of an unused array

template <typename ... Args>
void Print (Type const & type, std::string const & message,
Args const & ... arg)
{
using unused = int[];

std::stringstream strstr;

strstr << message << ": ";

(void)unused { 0, (strstr << arg << ", ", 0)... };

std::string toLog = strstr.str();

// Remove last separator characters.
toLog.erase(toLog.end() - 2, toLog.end());
Log(type, strstr.str());
}

How to call function that use part of template parameter pack in c++?

You might use std::index_sequence as helper:

template <typename Callable, typename Tuple, std::size_t... Is>
constexpr std::size_t is_invocable_args(std::index_sequence<Is...>)
{
return std::is_invocable_v<Callable, std::tuple_element_t<Is, Tuple>...>;
}

// Helper to know max number of args to take from tuple
template <typename Callable, typename Tuple, std::size_t... Is>
constexpr std::size_t max_invocable_args(std::index_sequence<Is...>)
{
std::array<bool, sizeof...(Is)> a = {
is_invocable_args<Callable, Tuple>(std::make_index_sequence<Is>{})...
};
auto rit = std::find(a.rbegin(), a.rend(), true);
if (rit == a.rend()) throw "no valid call";
return std::distance(a.begin(), rit.base()) - 1;
}

template <std::size_t N, typename Callable, typename Tuple>
constexpr std::size_t max_invocable_args()
{
return max_invocable_args<Callable, Tuple>(std::make_index_sequence<N + 1{});
}

// Call taking some element from tuple
template< typename Callable, std::size_t... Is, typename Tuple >
void Call_Tuple_impl(Callable cb, std::index_sequence<Is...>, Tuple&& args )
{
std::invoke(cb, std::get<Is>(std::forward<Tuple>(args))...);
}

template< typename Callable, typename ...Args >
void Call( Callable cb, Args... args )
{
constexpr std::size_t max_arg_count = max_invocable_args<sizeof...(Args), Callable, std::tuple<Args...>>();

Call_Tuple_impl(cb, std::make_index_sequence<max_arg_count>{}, std::forward_as_tuple(std::forward<Args>(args)...));
}

C++20 Demo

C++17 Demo with rewritten constexpr find.



Related Topics



Leave a reply



Submit