The code below doesn't compile (see error below the code). Can you please explain why?
template <class F, class... Arg>
void for_each_argument(F f, Arg&&... arg)
{
f(std::forward<Arg>(arg...));
}
int main()
{
for_each_argument(
[](const auto& a){std::cout<< a;}, "Aa", 3, 4);
return 0;
}
Here is an error message:
7:4: error: expression contains unexpanded parameter pack
'Arg'
f(std::forward(arg...));
You have several issues in your code. First of, your original line
f(std::forward<Arg>(arg...));
Is not correct syntax at all - you are expanding arg without properly expanding Arg in template. Now, you can fix at least that by
f(std::forward<Arg>(arg)...);
This would be better, but still wrong - you will call your lambda once with 3 arguments, while it only accepts one - and instead, you want to call lambda 3 times with a single argument.
There are several ways to do this. First, and the least preferred, is to call the function recursively, as other answer suggests. This prompts ugly syntax, and also adds burden on compiler for recursive template instantiation. Much better solution is to expand the argument using array trick, for example (ignoring the forward for simplicity):
auto lam = [&f](const auto& a) { f(a); return true;}
bool arr[] = { lam(std::forward<ARG>(arg))... };
(void)arr;
In C++ 17 you can use fold expression to achieve even more neat syntax:
(f(std::forward<ARG>(arg)), ...);
Expanding a parameter pack works in contexts that expect a comma separated list.
That is, your code:
f(std::forward<Arg>(arg...));
It attempting to expand into:
f( "Aa", 3, 4 );
And the lambda you have supplied does not support such a call.
To expand a parameter pack into multiple function calls, use a recursive function.
template <class F>
void for_each_argument(F f)
{
// (No args)
}
template <class F, class FirstArg, class... MoreArgs>
void for_each_argument(F f, FirstArg&& first_arg, MoreArgs&&... more_args)
{
f( std::forward<FirstArg>(first_arg) );
for_each_argument( f, std::forward<MoreArgs>(more_args)... );
}
Related
I'm sure this question has been asked before, but I can't seem to find something as simple as what I'm trying to do. Essentially, I just want to make sure the code triggers each parameter, calling any functions that may be sent as inputs. My biggest worry here is that optimizations may remove some of the calls, changing the result.
I was using the following syntax. It seemed to trigger the function calls the way I want, but it has the strange result of triggering the arguments in reverse order - the last argument is called first, and the first argument is called last:
template <typename... PARMS> uint PARMS_COUNT(PARMS&& ... parms) { return static_cast<uint>( sizeof...(parms) ); }
This was my first guess as to how to do the same thing (edit: this does not change the order - it still happens in reverse, because the order is being determined by the function parameter evaluation, rather than what order the function uses them in):
template <typename FIRST>
constexpr uint PARMS_EXPAND(FIRST &&first)
{
return static_cast<uint>( sizeof(first) > 0 ? 1 : 0 );
}
template <typename FIRST,typename... PARMS>
constexpr uint PARMS_EXPAND(FIRST &&first,PARMS&& ... parms)
{
return static_cast<uint>( sizeof(first) > 0 ? 1 : 0 ) + PARMS_EXPAND( std::forward<PARMS>(parms)... );
}
I tested this in a few places, but then realized that regardless of how much testing I do, I'll never know if this is a safe way to do it. Is there a standard or well known method to pull this logic off? Or even better, some built in system to iterate over the arguments and "access them" in the correct order?
To better explain why I would want to trigger code like this, consider a function that can add new objects to a parent:
void AddObject(/*SINGLE UNKNOWN INPUT*/)
{
...
}
template <typename... PARMS> AddObjects(PARMS&& ... parms)
{
PARAMS_EXPAND( AddObject(parms)... );
}
When you write
void AddObject(T);
template <typename... PARMS> AddObjects(PARMS&& ... parms)
{
PARAMS_EXPAND( AddObject(parms)... );
}
you're making a single top-level function call to PARAMS_EXPAND with sizeof...(PARMS) arguments.
What happens inside PARAMS_EXPAND is essentially irrelevant because, like every other function call, the arguments are evaluated before the function is entered. And, like every other function call, the argument expressions are intederminately sequenced with respect to each other.
So, your goal of evaluating AddObject(parms) for each parameter in order has failed before control reaches inside PARAMS_EXPAND at all.
Fortunately, C++17 gave us a way of evaluating operations on parameter packs in order without relying on function call semantics: the fold expression:
(AddObject(parms), ...);
Although this looks a bit like a function call, it's actually a right fold over the comma operator, expanded like
(AddObject(p0) , (... , (AddObject(pN-1) , AddObject(PN))));
which does indeed evaluate its arguments in left-to-right order, exactly as you want.
I answer the original question because it's not clear what you're asking for (see comment) later. If you want n arguments to be called in order, i.e. call operator() on them (e.g. for lambdas, functors), you can do:
constexpr void callEach() {}
template<typename F, typename... Fs>
constexpr void callEach(F f, Fs&&... fs)
{
f();
callEach(std::forward<Fs>(fs)...);
}
Any way that doesn't take lambdas cannot guarantee evaluation order.
In this line:
PARAMS_EXPAND( AddObject(parms)... );
the order of evaluation is not specified because there is no sequence point between each item. Also I'm confused as to why PARAMS_EXPAND does anything if you are going to discard the result. It might as well be this:
template <typename... PARMS>
void PARAMS_EXPAND(PARMS&&...) {}
If you just want to call AddObject with each parms in order, then you need to pass the function and the parameters separately:
void print(int i) {
std::cout << i << " ";
}
template <typename F, typename Head>
constexpr void call_for_each(F&& f, Head&& head)
{
f(head);
}
template <typename F, typename Head, typename... Tail>
constexpr void call_for_each(F&& f, Head&& head, Tail&&... tail)
{
f(std::forward<Head>(head));
call_for_each(std::forward<F>(f), std::forward<Tail>(tail)...);
}
template <typename... Args>
void print_all(Args&&... args)
{
call_for_each(print, std::forward<Args>(args)...);
}
Demo
Here the calls are correctly sequenced: first call f with head, then make the recursive call for the rest of the arguments in tail.
In C++17, you can use a fold expression instead:
template <typename F, typename... Args>
constexpr void call_for_each(F&& f, Args&&... args)
{
(f(std::forward<Args>(args)), ...);
}
Demo
This basically generates a line like so:
(f(std::forward<Args0>(args0), f(std::forward<Args1>(args1), ..., f(std::forward<ArgsN>(argsN));
where ArgsI and argsI are the I-th element of Args and args in the correct order.
Here, the calls are again correctly sequenced because of the comma operator.
Let's consider the following functions:
// run_cb_1(): Explicitly defined prototype
void run_cb_1(const std::function<void(int)> & callback, int p)
{
callback(p);
}
// run_cb_2(): One template parameter
template <typename T>
void run_cb_2(const std::function<void(T)> & callback, const T & t)
{
callback(t);
}
// run_cb_3(): Variable number of template parameters
template <typename ... Args>
void run_cb_3(const std::function<void(Args...)> & callback, const Args & ... args)
{
callback(args...);
}
Now if I want to use these functions as follows:
int main()
{
auto f = [](int a){
std::cout << a << '\n';
};
run_cb_1(f, 5); // OK
run_cb_2(f, 5); // KO --> I understand why
run_cb_2<int>(f, 5); // OK
run_cb_3(f, 5); // KO --> I understand why
run_cb_3<int>(f, 5); // KO --> I don't understand why...
return 0;
}
I get a "no matching function call" with run_cb_2() and run_cb_3() while it works perfectly fine with run_cb_1().
I think it behaves as expected because I did not provided the type for the template argument (since it can not be deduced trivially as it is for run_cb_1()).
But specifying the template type solves the problem for run_cb_2() (as I would expect) but not for run_cb_3().
I know I can solve it either by explicitly declaring f as:
std::function<void(int)> f = [](int a){
std::cout << a << '\n';
};
or by passing f as:
run_cb_2(std::function<void(int)>(f), 5);
run_cb_3(std::function<void(int)>(f), 5);
My question is: Why does the template argument deduction fail with run_cb_3() (with variadic template parameters) even when explicitly specifying the template type(s) ?
It is obvious that I missed something (maybe basic) but I don't know what it is.
Any help will be appreciated.
The reason this fails is because there isn't just one type the compiler can use. When you do
run_cb_2<int>(f, 5);
The compiler looks at run_cb_2 and sees that there is only one template parameter. Since you've provided that it skips the deduction phase and stamps out run_cb_2<int>.
With
run_cb_3<int>(f, 5);
You're in a different boat. run_cb_3 has a variadic template parameter which means just supplying int is not enough to skip the deduction. You specified the first argument, but there could be more so it goes into the argument deduction phase to figure it out. That means it checks callback to make sure what it deduces there matches what it deduces for args. Since the lambda is not a std::function it can't deduce Args... from it. Once that happens the compiler stops and issues an error.
With run_cb_3<int>, you don't explicitly provide full Args..., just the first type; it might have other.
It is used for example in function such as std::make_unique:
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args);
and
std::make_unique<MyObj>(var1, var2); // T = MyObj
// Args... = [decltype((var1)), decltype((var2))]
Extra args are deduced from argument.
To force evaluation, you might use:
(&run_cb_3<int>)(f, 5); // OK
Demo
What I am trying to accomplish is the following:
// or any templated function
template <typename... Args>
void function(Args... args) {}
// wrapper
void launch(???) { ??? }
int main()
{
// first option
launch(function, 1, 2, 3, 4);
// second option
launch<function>(1, 2, 3, 4);
}
As far as I can tell, the first option is impossibile since I would have to pass the specialized template function (which I'm trying to avoid).
For the second option I don't know if it's possible, I came up with the following not working implementation:
template <template <typename...> class Function, typename... Args>
void launch(Args... args)
{
Function<Args...>(args...);
}
which ends up giving me:
main.cpp:18:5: error: no matching function for call to 'launch'
launch<function>(1, 2, 3, 4);
^~~~~~~~~~~~~~~~
main.cpp:9:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Function'
void launch(Args... args)
^
1 error generated.
So, is something like this even possible?
You basically cannot do anything with function templates except call them (and let arguments get deduced) or instantiate them (by manually specifying template arguments).
I believe there are also niche situations where template arguments may be deduced and a specific instantiation chosen without an actual call, but they don't help here AMA's answer shows how to do that!
Generic lambdas may or may not help you solve your problem, but you need one such forwarding lambda per function template you want to make "passable":
#include <functional>
// or any templated function
template <typename Arg1, typename Arg2>
void function(Arg1 arg1, Arg2 arg2) {}
int main()
{
auto wrapper = [](auto arg1, auto arg2) {
return function(arg1, arg2);
};
std::invoke(wrapper, 1, 2);
}
Demo
(Perfect-forwarding to a variadic function with a variadic lambda would be more complicated.)
So you might as well write function templates in the form of functor structs in the first place, or in the form of lambdas returned from non-template functions.
How about:
template <typename ... Args>
void launch(void(*func)(Args...), Args&&... args) {
func(std::forward<Args>(args)...);
}
calling launch:
launch(function, 1, 2, 3, 4);
Live example
The idiomatic way would be to infer the type of the callable, as if it was any type, and not care about the template-ness of the thing:
template <typename F, typename ... Args>
auto launch(F f, Args&&... args) -> decltype(auto) {
return f(std::forward<Args>(args)...);
}
It also will forward the return value of the function.
Then, to send your templated function, you must lift the function into a lambda:
auto function_lift = [](auto&&... args)
noexcept(noexcept(function(std::forward<decltype(args)>(args)...)))
-> decltype(function(std::forward<decltype(args)>(args)...))
{
return function(std::forward<decltype(args)>(args)...);
};
// also works with defaulted parameters.
launch(function_lift, 1, 2, 3, 4);
Creating those lifted function is very verbose. The answer to verbose-ness in this case is of course a macro:
#define LIFT(lift_function) [](auto&&... args) \
noexcept(noexcept(lift_function(std::forward<decltype(args)>(args)...))) \
-> decltype(lift_function(std::forward<decltype(args)>(args)...)) \
{ \
return lift_function(std::forward<decltype(args)>(args)...); \
}
Now you can call your wrapper:
launch(LIFT(function), 5, 4, 3, 2);
I'm trying to create a way to directly expand multiple parameter packs. I have created a function template<size_t X,typename F> auto sequenceFunc(F&& f), that calls a given function f with a expanded integer_sequence.
This works well for small functions like this:
template<typename T,
size_t A,size_t B>
vec<B,T> col(const mat<A,B,T>& a,const size_t& i){
return sequenceFunc<A>([&](auto... J) -> vec<B,T>{
return { a[J][i]... }; //expands to a[0][i], a[1][i], ... a[A-1][i]
});
}
Unfortunately I can't expand multiple parameter packs, even if I follow the rule, that only one parameter pack can be inside a ...-expression.
This is my attempt at using this function for matrix multiplication:
template<typename S,typename T,
size_t A,size_t B,size_t C>
mat<C,B,S> mul(const mat<A,B,S>& a,const mat<C,A,T>& b){
return sequenceFunc<B>([&](auto... I)->mat<C,B,S>{ //for all B rows in a...
return {
sequenceFunc<C>([&](auto... J)->vec<C,S>{ // ... look at all C columns in b and calculate dot product.
auto i = I; //putting "I" outside the expansion of "J"
return {
dot(row(a,i),col(b,J))... //expands J
};
})... //expands I
};
});
}
This is the error:
error: parameter packs not expanded with '...':
auto i = I;
^
I don't really understand why an expansion is necessary, because there is another ... outside the expression. I use GCC 5.1.0.
Information vec and mat are only using-declarations for std::array and a nested std::array<std::array<A,T>,B>
This is gcc bug 47226. It's still open, and the code example still fails on gcc 5.2.0, while it compiles just fine on clang 3.6. Your code looks correct to me.
I just encountered the same problem. Didnt find a better dupe and didnt want to open a new question, but still want to share my findings. In a comment to a similar question I found a workaround that puts the parameters in a tuple and then unpacks it inside the lambda (sorry dont find the link anymore). However, that solution requires C++17 (std::apply and more).
My case was something like this:
struct Foo{
template <typename T,typename ...ARGS>
void foo(T t,ARGS...args){
auto x = [&](){ t(args...);}
}
};
which is not working with gcc 4.8.5. To my surprise, simply explicitly writing out the lambda as functor works like a charm:
template <typename T,typename ...ARGS>
struct FooFunct{
void operator()(T t,ARGS...args){
t(args...);
}
};
struct Foo{
template <typename T,typename ...ARGS>
void foo(T t,ARGS...args){
auto x = FooFunct<T,ARGS...>();
}
};
I find it a bit strange, that gcc swallows this, while not the first one. Afaik lambdas are just syntactic sugar for anonymous functors on function scope. Probably my knowledge on compilers is just too little to understand what is the problem in fixing this bug.
Following with the tuple continuation monad, say I define a functor std_tuple to go from the cathegory of the monad-tuple to std::tuple:
auto std_tuple = [](auto... args)
{
return [=](auto f){ return f(std::make_tuple(args...)); };
};
Now we can use monad-tuples in contexts expecting std::tuple:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main()
{
tuple(1,2,3)(std_tuple)(f);
}
So far so good. Except this doesn't compile. Clang 3.4.1 complains:
note: candidate template ignored: couldn't infer template argument '$auto-1-0'
on the f(t) call inside the std_tuple functor.
Is this correct, are not those template argumments deducible? In case afirmative, why?
A simple case that reproduces your problem:
void f(int) {}
void f(double) {}
template<class T> void call_with_3( T t ) { t(3); }
int main() {
call_with_3( f );
}
Here we can see that which f to call cannot be determined at the point where we pass it to call_with_3. Now, you seemingly don't have multiple overloads (you only have one f!), but...
A template is not an instance. A template function is a factory of functions, not a function.
There is no object or value there to pass around.
When you pass a function name as an argument, overload resolution kicks in. If the target type is known (as a function reference or pointer) it is used to do overload resolution on the function name.
In this case, you are passing a function name to a template (auto argument), so there is no overload resolution that can be done, so no particular value can be found, so you get an error.
You can create an object whose effect is to do overload resolution on the invoked arguments with a given function name. I call them overload set objects.
static struct f_overload_set_t {
template<class... Args>
auto operator()(Args&&... args) const {
return f(std::forward<Args>(args)...);
}
} f_overload_set;
in C++11 you need a ->decltype( f( std::declval<Args>()... ) ) after the const.
Now f_overload_set(blah) will, when invoked will (almost) do what happens when you f(blah), but f_overload_set is an actual object. So you can pass it around.
Macros that generate such overload sets are relatively easy to write. They can also use lambdas, as the above is a lot like a stateless lambda if you think about it.
The nice thing about the stateless lambda based macro overload set generator is that it can be created at point-of-use. From #dyp's comment above:
#define OVERLOAD_SET( FUNC )\
([](auto&&... args){\
return FUNC(std::forward<decltype(args)>(args)...);\
})
(note: no brackets around FUNC, as that blocks ADL). Brackets around everything else, because otherwise if used within a subscript operation (operator[]), it would be parsed as a [[ starting an attribute, among other spots (thanks to #ecatmur))
which makes your code:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main() {
tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f));
}