Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do I get "candidate expects 2 arguments, 1 provided" compilation error when forwarding functions with C++11?

I’m trying to understand function forwarding with lambdas on C++ by running this code:

#include <functional>

template<typename Func, typename... Args>
int do_something_1(int foo_1, Func&& func, Args&&... args, int foo_0 = 0) { 
    int var_1 = foo_0 + 2 * foo_1; 
    return std::forward<Func>(func)(var_1, std::forward<Args>(args)...);
};

int main (void) {
    return do_something_1(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
}

However it fails with this compilation error:

<source>: In instantiation of 'int do_something_1(int, Func&&, Args&& ..., int) [with Func = main()::<lambda(int, int)>; Args = {}]':
<source>:11:93:   required from here
<source>:7:36: error: no match for call to '(main()::<lambda(int, int)>) (int&)'
    7 |     return std::forward<Func>(func)(var_1, std::forward<Args>(args)...);
      |            ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:7:36: note: candidate: 'int (*)(int, int)' (conversion)
<source>:7:36: note:   candidate expects 3 arguments, 2 provided
<source>:11:30: note: candidate: 'main()::<lambda(int, int)>'
   11 |     return do_something_1(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
      |                              ^
<source>:11:30: note:   candidate expects 2 arguments, 1 provided

And I don’t know how to correct it.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Non-terminal function parameter packs are a "non-deduced context" ([temp.deduct.type]/5):

The non-deduced contexts are:

  • […]
  • A function parameter pack that does not occur at the end of the parameter-declaration-list.

This means that the 4 which you pass as an argument will not be used to deduce Args, but is instead bound to foo_0.

Technically you can make this compile by providing template arguments explicitly:

int main (void) {
    return do_something_1<int(*)(int,int), int>(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
}

This works because the non-capturing lambda can convert to a function pointer, and explicitly supplying int as a second template argument causes the 4 to bind to args... instead of foo_0.

But in general I’d recommend avoiding non-terminal function parameter packs when possible.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading