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

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

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:

  1. #include <functional>
  2. template<typename Func, typename... Args>
  3. int do_something_1(int foo_1, Func&& func, Args&&... args, int foo_0 = 0) {
  4. int var_1 = foo_0 + 2 * foo_1;
  5. return std::forward<Func>(func)(var_1, std::forward<Args>(args)...);
  6. };
  7. int main (void) {
  8. return do_something_1(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
  9. }

However it fails with this compilation error:

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

  1. #include &lt;functional&gt;
  2. template&lt;typename Func, typename... Args&gt;
  3. int do_something_1(int foo_1, Func&amp;&amp; func, Args&amp;&amp;... args, int foo_0 = 0) {
  4. int var_1 = foo_0 + 2 * foo_1;
  5. return std::forward&lt;Func&gt;(func)(var_1, std::forward&lt;Args&gt;(args)...);
  6. };
  7. int main (void) {
  8. return do_something_1(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
  9. }

However it fails with this compilation error:

  1. &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;:
  2. &lt;source&gt;:11:93: required from here
  3. &lt;source&gt;:7:36: error: no match for call to &#39;(main()::&lt;lambda(int, int)&gt;) (int&amp;)&#39;
  4. 7 | return std::forward&lt;Func&gt;(func)(var_1, std::forward&lt;Args&gt;(args)...);
  5. | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  6. &lt;source&gt;:7:36: note: candidate: &#39;int (*)(int, int)&#39; (conversion)
  7. &lt;source&gt;:7:36: note: candidate expects 3 arguments, 2 provided
  8. &lt;source&gt;:11:30: note: candidate: &#39;main()::&lt;lambda(int, int)&gt;&#39;
  9. 11 | return do_something_1(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
  10. | ^
  11. &lt;source&gt;:11:30: note: candidate expects 2 arguments, 1 provided

And I don't know how to correct it.

答案1

得分: 1

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

你正在调用

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

通过

  1. 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

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

via

  1. 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

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

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

这可以工作,因为非捕获 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:

  1. int main (void) {
  2. return do_something_1&lt;int(*)(int,int), int&gt;(1, [](int var_1, int local_var) { return (var_1 + local_var); }, 4);
  3. }

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:

确定