[英]Variadic template function accepting lambda
I'm trying to understand the compiler error that I'm getting fo the code below. 我试图理解我在下面的代码中得到的编译器错误。 I've got a variadic template function which accepts a lambda with the specified types, and attempting to call that function results in the template not being considered a valid candidate due to a mismatch.
我有一个可变参数模板函数,它接受一个具有指定类型的lambda,并且尝试调用该函数会导致模板由于不匹配而不被视为有效候选。
#include <functional>
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{
}
int main(int argc, char **argv)
{
executeWithResultHandler<int>([] (int arg) {
});
return 0;
}
This results in the following error: 这会导致以下错误:
$ c++ -std=c++11 reduction.cpp
reduction.cpp:10:5: error: no matching function for call to 'executeWithResultHandler'
executeWithResultHandler<int>([] (int arg) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduction.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against
'<lambda at reduction.cpp:10:35>'
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
^
1 error generated.
If I change the declaration to not be variadic: 如果我将声明更改为variadic:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
then it works for the toy example above, but for the real problem I need arbitrary arguments. 然后它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。 Is there something I'm missing here, or anther way to accomplish this?
有没有我在这里缺少的东西,或者其他方法来实现这一目标?
EDIT: This was marked as a duplicate incorrectly, I believe- the dupe does not answer the question I'm asking. 编辑:这被标记为重复不正确,我相信 - 这个骗局没有回答我问的问题。 This question specifically has to do with the variadic template issue here: Please note that, when I switch the template to be non-variadic the lambda converts to the std::function type correctly, as expected.
这个问题特别与这里的可变参数模板问题有关:请注意,当我将模板切换为非可变参数时,lambda正确地转换为std :: function类型,如预期的那样。 This is true regardless of the number of arguments, as long as that is not handled in a variadic fashion.
无论参数的数量是多少都是如此,只要不以可变方式处理。
However, it does not work with the variadic version specifically, despite an expectation that the parameter pack is unpacked to a set of real parameters, and the explicit specification of the template parameter list at the function call site. 但是,它没有特别适用于可变参数版本,尽管期望参数包被解包为一组实际参数,并且在函数调用站点显式指定模板参数列表。
The problem with variadic templates in your case is that the compiler does not know whether the int
you explicitly specified is the complete list for ResultTypes...
or not, so it tries to deduce the optional remaining arguments from the parameter you gave it, and that obviously fails. 在你的情况下,可变参数模板的问题是编译器不知道你明确指定的
int
是否是ResultTypes...
的完整列表ResultTypes...
所以它试图从你给它的参数中推导出可选的剩余参数,并且这显然是失败的。 This is a common pitfall with variadic template arguments and it is not limited to lambdas. 这是可变参数模板参数的常见缺陷,并不仅限于lambdas。
A solution always implies that you take away this option from the compiler, eg 解决方案始终意味着您从编译器中删除此选项,例如
template<typename ... ResultTypes>
void executeWithResultHandler_impl(std::function<void (ResultTypes...)> lambda)
{
}
template<typename ... ResultTypes, typename F>
void executeWithResultHandler(F&& lambda)
{
executeWithResultHandler_impl(std::function<void (ResultTypes...)>(lambda));
}
The question I'd previously linked as duplicate explains exactly what is going in your case. 我之前将其作为重复链接的问题可以准确地解释您的情况。
An std::function
is not a lambda, it is type of container that can store any kind of callable object. std::function
不是 lambda,它是可以存储任何类型的可调用对象的容器类型。 You can assign a lambda to an std::function
, but in that case the necessary conversion is performed by the std::function
constructor. 您可以将lambda分配给
std::function
,但在这种情况下,必需的转换由std::function
构造std::function
执行。
In your example 在你的例子中
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
the compiler has no way of inferring the types in the parameter pack ResultTypes
from the lambda expression above. 编译器无法从上面的lambda表达式推断参数包
ResultTypes
的类型。 Template argument deduction requires exact matches, implicit conversions are not considered, and the types involved here, as mentioned earlier, are completely different. 模板参数推导需要完全匹配,不考虑隐式转换,并且如前所述,此处涉及的类型完全不同。
If I change the declaration to not be variadic then it works
如果我将声明更改为variadic,那么它可以工作
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
This works because there's no template argument deduction involved anymore. 这是有效的,因为不再涉及模板参数推断。
executeWithResultHandler
takes exactly one template parameter, which you've explicitly specified, and because a lambda is implicitly convertible to std::function
, overload resolution will find a match. executeWithResultHandler
接受一个你明确指定的模板参数,并且因为lambda可以隐式转换为std::function
,所以重载解析会找到匹配项。
Note that in the first case there may have been more template arguments, in addition to int
, that you hadn't specified explicitly. 请注意,在第一种情况下,除了
int
之外,可能还有更多的模板参数,您没有明确指定。
You can get your original example to work by explicitly converting the lambda to std::function
. 您可以通过将lambda显式转换为
std::function
来获得原始示例。
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.