英文:
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 <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.
答案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_1
是 1
,foo_0
是 4
,且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<typename Func, typename... Args>
int do_something_1(int foo_1, Func&& func, Args&&... 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<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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论