How to Iterate over a parameter pack - c++14

I need to define a function with template parameter pack with C++14.
The caller of the function makes sure that the size of Args... must be even, such as 2, 4, 6... And my function will pass them two by two to two functions.
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... params) {
using params_t = std::tuple<Args...>;
auto tp = std::make_tuple(params...);
for (std::size_t i = 0; i < sizeof...(Args); ++i) {
f(std::get<i>(tp));
f2(std::get<++i>(tp));
}
}
// caller
func(f1, f2, "abc", 3, "def", "ppp");
This won't work because i is not a constant expression.
What could I do? Is it the right and the only way to iterate over a parameter pack with std::tuple?

To use a std::tuple to iterate over a parameter pack, you would usually use a std::index_sequence to introduce a new pack of indices, and use a fold expression to do the actual iteration. Something like this:
template<typename F, typename F2, typename... Args, std::size_t... I>
void func_impl(F& f, F2& f2, std::tuple<Args...> params, std::index_sequence<I...>) {
// This would be a fold expression over a comma in C++17:
/*
(([&]{}(
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
)), ...);
*/
// C++14 version
using consume = int[];
(void) consume{ 0, [&]{
f(std::get<I*2>(params));
f2(std::get<I*2+1>(params));
return 0;
}()... };
}
template<typename F, typename F2, typename... Args>
void func(F f, F2 f2, Args&&... args) {
static_assert(sizeof...(args) % 2 == 0, "Must pass a multiple of 2 args to func");
func_impl(
f, f2,
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<sizeof...(args) / 2>{}
);
}
But you can also iterate with recursion, which might be easier in your case:
template<typename F, typename F2>
void func(F&& f, F2&& f2) {
// base case: do nothing
}
template<typename F, typename F2, typename Arg1, typename Arg2, typename... Args>
void func(F&& f, F2&& f2, Arg1&& arg1, Arg2&& arg2, Args&&... args) {
// recursive case
f(arg1);
f2(arg2);
func(std::forward<F>(f), std::forward<F2>(f2), std::forward<Args>(args)...);
}

Related

Call function with part of variadic arguments

Consider I have the following:
void bar(int a, int b)
{
}
template<typename F, typename... Args>
void foo(F function, Args... args>
{
function(args...);
}
I would like to have some kind of way to only pass the necessary amount of arguments to the function, so that I would be able to do the following, which should result in a call to bar with 1, 2 as arguments discarding the 3. Without knowing how many arguments the passed in function type F needs.
foo(bar, 1, 2, 3);
foo([](int a, int b){}, 1, 2, 3);
When I try to use the below function traits:
namespace detail
{
template<typename F, std::size_t... Is, class Tup>
void call_discard_impl(F&& func, std::index_sequence<Is...>, Tup&& tup)
{
std::forward<F>(func)(std::get<Is>(tup)...);
}
}
template<typename F, typename... Args>
void call_discard(F&& func, Args&&... args)
{
detail::call_discard_impl(std::forward<F>(func),
std::make_index_sequence<function_traits<F>::num_args>{},
std::forward_as_tuple(args...));
}
I get:
error C2510: 'F': left of '::' must be a class/struct/union
error C2065: '()': undeclared identifier
error C2955: 'function_traits': use of class template requires template argument list
On:
template <typename F>
struct function_traits : public function_traits<decltype(&F::operator())>
{}
I did get the member function version working which did not require the function traits:
namespace detail
{
template<typename O, typename R, typename... FunArgs, std::size_t... Is, class Tup>
void call_discard_impl(O* obj, R(O::*mem_func)(FunArgs...), std::index_sequence<Is...>, Tup&& tup)
{
((*obj).*mem_func)(std::get<Is>(tup)...);
}
}
template<typename O, typename R, typename... FunArgs, typename... Args>
void call_discard(O* obj, R(O::*mem_func)(FunArgs...), Args&&... args)
{
detail::call_discard_impl(obj, mem_func,
std::make_index_sequence<sizeof...(FunArgs)>{},
std::forward_as_tuple(args...));
}
First, use the following code that lets you find the arity of a lambda or function reference:
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <typename R, typename ... Args>
struct function_traits<R(&)(Args...)>
{
using result_type = R;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
Next, you forward the variadic arguments along using a tuple pack, and you only expand out to the arity of the function:
template<typename F, std::size_t... Is, class T>
void foo_impl(F && f, std::index_sequence<Is...>, T && tuple) {
std::forward<F>(f)(std::get<Is>(tuple)...);
}
template<typename F, typename... Args>
void foo(F && f, Args&&... args) {
foo_impl(std::forward<F>(f),
std::make_index_sequence<function_traits<F>::arity>{},
std::forward_as_tuple(args...) );
}
Live example: http://coliru.stacked-crooked.com/a/3ca5df7b55c427b8.
First, we need a function to retrieve the number or arguments the function requires. This is done using function_traits:
template <class F>
constexpr std::size_t nb_args() {
return utils::function_traits<F>::arity;
}
And with the help of std::index_sequence, we only dispatch the nb_args<F>() first arguments:
template<typename F, std::size_t... Is, class Tup>
void foo_impl(F && f, std::index_sequence<Is...>, Tup && tup) {
std::forward<F>(f)( std::get<Is>(tup)... );
}
template<typename F, typename... Args>
void foo(F && f, Args&&... args) {
foo_impl(std::forward<F>(f),
std::make_index_sequence<nb_args<F>()>{},
std::forward_as_tuple(args...) );
}
Demo
Trivial and hardly extensible solution would be to create a wrapper, that will be called with all arguments, but will use only first few of them.
template<typename F, typename... Args>
void foo(F function, Args... args)
{
// with proper forwarding if needed
auto lambda = [](auto fnc, auto first, auto second, auto...)
{
fnc(first, second);
};
lambda(function, args...);
}
Here is a solution that will work with anything std::invoke accepts, that invokes the overload with the fewest possible arguments.
template <typename F, typename Args, std::size_t... In>
decltype(auto) invoke_front_impl(F&& f, Args&& args, std::index_sequence<In...>)
{
if constexpr (std::is_invocable_v<F&&, std::tuple_element_t<In, Args>...>) {
return std::invoke(std::forward<F>(f), std::get<In>(std::move(args))...);
} else {
return invoke_front_impl(
std::forward<F>(f),
std::move(args),
std::make_index_sequence<sizeof...(In) + 1>());
}
}
template <typename F, typename... Args>
decltype(auto) invoke_front(F&& f, Args&&... args)
{
return invoke_front_impl(
std::forward<F>(f),
std::forward_as_tuple(std::forward<Args>(args)...),
std::make_index_sequence<0>());
}
Demo on Wandbox

boost::range::combine with repeated argument

I would like to use boost::range::combine as a cartesian power instead as just a product.
So instead of such expression boost::range::combine(myRange, myRange, myRange); write something like myCombine(myRange, 3);.
How it can be implemented?
Implementing this in C++17 or C++14 would be a lot easier and cleaner, but since you tagged this with c++11 here's a compliant implementation. Here's a generic way of calling a function object f with the same argument repeated N times.
First, we need a way of binding the first argument of a generic function object f and then accepting any number of arguments:
template <typename TF, typename T>
struct bound
{
TF _f;
T _x;
template <typename TFFwd, typename TFwd>
bound(TFFwd&& f, TFwd&& x)
: _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)}
{
}
template <typename... Ts>
auto operator()(Ts&&... xs)
-> decltype(_f(_x, std::forward<Ts>(xs)...))
{
return _f(_x, std::forward<Ts>(xs)...);
}
};
template <typename TF, typename T>
auto bind_first(TF&& f, T&& x)
-> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)))
{
return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x));
}
Then, we need a recursive helper that will bind an argument x multiple TN times:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x))
{
return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
auto operator()(TF&& f, T&& x)
-> decltype(f(x))
{
return f(x);
}
};
Finally, we can provide a nice interface:
template <std::size_t TN, typename TF, typename T>
auto call_with_same_arg(TF&& f, T&& x)
-> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)))
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
Usage:
int add(int a, int b, int c)
{
return a + b + c;
}
int main()
{
assert(call_with_same_arg<3>(add, 5) == 15);
}
live wandbox example
Here's a complete C++17 implementation of the same thing:
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
if constexpr(TN == 1)
{
return f(x);
}
else
{
return call_with_same_arg<TN - 1>(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
}
live wandbox example
For completeness, C++14 implementation:
template <std::size_t TN>
struct helper
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return helper<TN - 1>{}(
[&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
}
};
template <>
struct helper<0>
{
template <typename TF, typename T>
decltype(auto) operator()(TF&& f, T&& x)
{
return f(x);
}
};
template <std::size_t TN, typename TF, typename T>
decltype(auto) call_with_same_arg(TF&& f, T&& x)
{
return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
}
live wandbox example

Variadic template function overloading

I have a class with a variadic template member function (foo) like below. The idea is to skip all doubles in the parameter and allocate an object with user provided arguments.
template <class T>
class Var {
public:
template <typename U, typename ...Args>
int foo(int index, Args... args)
{
T* p = new U(args...);
// save in an array at index 'index'
}
template <typename U, typename ...Args>
int foo (double index, Args... args)
{
// do something with index and skip it
return foo<U>(args...);
}
};
class A {
public:
A (int i, const char *p)
{
}
};
int main ()
{
Var<A> var;
var.foo<A>(1.0, 2, 3, "Okay");
}
Now this works, there are 2 problem.
Enforce how many doubles to skip.Eg: skip 2 doubles and then the next argument should be an int. If it is not then throw error.
While at it, use 'int' in place of 'double'. So we will skip 2 ints. The next index will be a 'index' to an array.
Basically I want to pass the no. of ints to skip as class template parameter.
template <class T, int SKIP>
class Var {
And use SKIP to determine how many ints to skip.
Is it possible to do something like that?
For your SKIP goal, you could do something like this:
template <typename U, typename ...Args>
int foo(Args ...args) {
return foo_helper<U, 0>(std::forward(args));
}
template <typename U, int I, typename ...Args>
int foo_helper(int index, Args ...args) {
return foo_helper<U, I+1>(std::forward(args));
}
template <typename U, typename ...Args>
int foo_helper<U, SKIP, Args...>(int index, Args ...args) {
blah = new U(std::forward(args));
return foobar;
}
Basically, have methods that count up to the target and strip off arguments until it's reached. Make a specialization for the target value.
Also, not that you'll probably want to forward the arguments to preserve references, etc.
I believe C++14 might make some of this easier, but I'm not familiar enough with newer template metaprogramming techniques to address that.
So this is what I conjured up taking hint from Novelocrat. Just pasting it hear for the records.
template <class T, int SKIP>
class FooHelper {
public:
template <typename U, typename ...Args>
static int foo_helper(int index, Args... args)
{
FooHelper<T, SKIP-1>::foo_helper<U>(args...);
return 0;
}
};
template <class T>
class FooHelper<T, 0> {
public:
template <typename U, typename ...Args>
static int foo_helper (Args... args)
{
auto p = new U(args...);
return 0;
}
};
template <class T, int SKIP>
class Var {
public:
template <typename U, typename ...Args>
int foo(Args ...args)
{
FooHelper<T, SKIP>::foo_helper<U>(args...);
return 0;
}
};

how to recursive acquire variadic function parameter with variadic template argument in c++ 11?

I'm working on my own Lua engine with C++ 11, I want to write a function wrapper that register C++ function to Lua environment with variadic parameter. That's simple in C++ 0x, but boring cause I need to write similar codes to support function with 0~N parameters.
function push is used to push T to lua stack, where function upvalue_ get C++ function pointer with lua cclosure, and it assume the funtion is has two parameters T1 and T2, T1 is acquired from lua stack with index 1, and T2 is acquired from lua stack with index 2.
template <typename RVal, typename T1, typename T2>
struct functor<RVal,T1,T2>
{
static int invoke(lua_State *L)
{
push(L,upvalue_<RVal(*)(T1,T2)>(L)(read<T1>(L,1),read<T2>(L,2)));
return 1;
}
};
template<typename T>
T upvalue_(lua_State *L)
{
return user2type<T>::invoke(L, lua_upvalueindex(1));
}
and with C++ 11, I wrote such code snippets:
template< typename RVal, typename ... ARGS>
struct functor
{
static int invoke(lua_State* L)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read_stack<ARGS>(L)...));
return 1;
}
};
template<typename T>
T read_stack(lua_State* L)
{
T t = read<T>(L, -1);
lua_pop(L, 1);
return t;
}
the code shown above could work, but the parameter order is reversed because read_stack read parameter from the last index -1 always.
my question is how to read parameter from lua stack from 1 to N(N equals to sizeof...(ARGS) if ARGS not empty) with variadic template argument and pass them to real function pointer f to make real call?
Not specific to Lua, here is a general-purpose C++11 solution to reversing the order of given parameters to a function. In the below code, 'apply' is my example target function (here it just outputs a bit of text based on its variadic parameters). The 'main' functions shows how the helper function 'reverse_and_apply' takes a function (or Functor to be precise) and a set of arguments, and applies the given function to the reversed argument list using some template trickery. Note I apologise for the somewhat anal use of perfect forwarding here, which is technically correct but unfortunately obfuscates the code somewhat. Hopefully you get the main message.
#include <iostream>
template <typename ...Args>
void apply(const char* fmtString, const Args&... args)
{
char output[512];
snprintf(output, 512, fmtString, args...);
std::cout << output << std::endl;
}
template <typename F, typename ...Args>
struct ReverseAndApply;
template <typename F>
struct ReverseAndApply<F>
{
template <typename ... AlreadyReversed>
static void doIt(F func, AlreadyReversed&& ... args)
{
func(args...);
}
};
template <typename F, typename FirstArg, typename ...RestArgs>
struct ReverseAndApply<F, FirstArg, RestArgs...>
{
template <typename ... AlreadyReversed>
static void doIt(F func, FirstArg&& arg, RestArgs&& ... restArgs, AlreadyReversed&& ... revArgs)
{
ReverseAndApply<F, RestArgs...>::doIt(func, std::forward<RestArgs>(restArgs)..., std::forward<FirstArg>(arg), std::forward<AlreadyReversed>(revArgs)...);
}
};
template <typename F, typename... Args>
void reverse_and_apply(F func, Args&&... args)
{
ReverseAndApply<F, Args...>::doIt(func, std::forward<Args>(args)...);
}
int main()
{
reverse_and_apply(apply<double, const char*, int>, 1, (const char*)"abc", 2.0, "%f %s %d");
return 0;
}
Your code in C++11 not even work as the evaluation order of arguments is not defined.
It should be easy by using std::integer_sequence in C++14.
Sample code:
template< typename RVal, typename... ARGS>
struct functor
{
template <std::size_t... Is>
static int invoke_impl(lua_State *L, std::index_sequence<Is...>)
{
typedef RVal (*FUNC_PTR)(ARGS...);
FUNC_PTR f = upvalue_<FUNC_PTR>(L);
push(L, f(read<ARGS>(L, Is)...));
return 1;
}
static int invoke(lua_State* L)
{
return invoke_impl(L, std::index_sequence_for<ARGS...>{});
}
};

variadic template parameter pack expanding for function calls

I am looking for something like that:
template< typename T>
void func(T t)
{
}
template< typename... Parms>
void anyFunc( Parms... p)
{
func<Parms>(p)... ; //error
func(p)... ; //error
}
If the parameter pack expansion is done inside another function call it works:
template< typename T>
int some(T t)
{}
template< typename... Parms>
void func(Parms ...p)
{}
template< typename... Parms>
void somemore(Parms... p)
{
func( some(p)...);
}
int main()
{
somemore(1,2,3,4,10,8,7, "Hallo");
}
The parameter pack expansion will also work for a list of base class initializers.
Is there any solution which will also work for functions which will return 'void'. The above workaround will not, while using the function calls returning void inside a parameter list could never work.
Any ideas?
Unfortunately, as you noticed, expanding a parameter pack is only valid in certain contexts where the parser expects a comma-separated list of entries – contexts where the comma is just a syntactic separator, not the comma operator. This is arguably a deficiency in the current text.
An ugly workaround:
func((some(p), 0)...);
Do note that the evaluation order of function arguments, and thus the order of the some invocations, is unspecified, so you have to be careful with any side effects.
How about a small helper class:
template <typename Func, typename A, typename ...Args> struct Caller
{
static void call(Func & f, A && a, Args && ...args)
{
f(std::forward<A>(a));
Caller<Func, Args...>::call(f, std::forward<Args>(args)...);
}
};
template <typename Func, typename A> struct Caller<Func, A>
{
static void call(Func & f, A && a)
{
f(std::forward<A>(a));
}
};
template <typename Func, typename ...Args>
void Call(Func & f, Args && ...args)
{
Caller<Func, Args...>::call(f, std::forward<Args>(args)...);
}
Then you can put the following in your client code:
void foo(A);
Call(foo, a1, a2, a3);

Resources