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

huangapple go评论63阅读模式
英文:

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.

英文:

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

#include &lt;functional&gt;

template&lt;typename Func, typename... Args&gt;
int do_something_1(int foo_1, Func&amp;&amp; func, Args&amp;&amp;... args, int foo_0 = 0) { 
    int var_1 = foo_0 + 2 * foo_1; 
    return std::forward&lt;Func&gt;(func)(var_1, std::forward&lt;Args&gt;(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:

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

And I don't know how to correct it.

答案1

得分: 1

这与转发无关,只是使错误更难发现。

你正在调用

template<typename Func, typename... Args>
int do_something_1(int foo_1, Func&& func, Args&&... args, int foo_0 = 0)

通过

do_something_1(1, ...lambda..., 4);

即,foo_11foo_04,且sizeof...(args)==0

不确定你想传递给 lambda 的是什么。然而,问题在于你只传递了 1,而期望传递 2 个参数。

英文:

This has nothing to do with forwarding. Its just making the error more difficult to spot.

You are calling

template&lt;typename Func, typename... Args&gt;
int do_something_1(int foo_1, Func&amp;&amp; func, Args&amp;&amp;... args, int foo_0 = 0)

via

do_something_1(1, ...lambda..., 4);

ie, foo_1 is 1, foo_0 is 4 and sizeof...(args)==0.

Not sure what you wanted to pass to the lambda. However, the issue is that you pass only 1 when 2 arguments are expected.

答案2

得分: 1

非终端函数参数包是一个“非推导上下文”([temp.deduct.type]/5):

非推导上下文包括:

  • [...]
  • 不出现在参数声明列表末尾的函数参数包。

这意味着您将作为参数传递的 4 不会用于推导 Args,而是绑定到 foo_0

从技术上讲,您可以通过显式提供模板参数来使其编译通过:

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

这可以工作,因为非捕获 lambda 可以转换为函数指针,并且显式提供 int 作为第二个模板参数会导致 4 绑定到 args... 而不是 foo_0

但通常情况下,我建议尽量避免在非终端函数参数包中使用这种方法。

英文:

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&lt;int(*)(int,int), int&gt;(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.

huangapple
  • 本文由 发表于 2023年4月17日 17:15:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76033519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定