[英]Variadic template function accepting lambda
我试图理解我在下面的代码中得到的编译器错误。 我有一个可变参数模板函数,它接受一个具有指定类型的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;
}
这会导致以下错误:
$ 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.
如果我将声明更改为variadic:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
然后它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。 有没有我在这里缺少的东西,或者其他方法来实现这一目标?
编辑:这被标记为重复不正确,我相信 - 这个骗局没有回答我问的问题。 这个问题特别与这里的可变参数模板问题有关:请注意,当我将模板切换为非可变参数时,lambda正确地转换为std :: function类型,如预期的那样。 无论参数的数量是多少都是如此,只要不以可变方式处理。
但是,它没有特别适用于可变参数版本,尽管期望参数包被解包为一组实际参数,并且在函数调用站点显式指定模板参数列表。
在你的情况下,可变参数模板的问题是编译器不知道你明确指定的int
是否是ResultTypes...
的完整列表ResultTypes...
所以它试图从你给它的参数中推导出可选的剩余参数,并且这显然是失败的。 这是可变参数模板参数的常见缺陷,并不仅限于lambdas。
解决方案始终意味着您从编译器中删除此选项,例如
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));
}
我之前将其作为重复链接的问题可以准确地解释您的情况。
std::function
不是 lambda,它是可以存储任何类型的可调用对象的容器类型。 您可以将lambda分配给std::function
,但在这种情况下,必需的转换由std::function
构造std::function
执行。
在你的例子中
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
编译器无法从上面的lambda表达式推断参数包ResultTypes
的类型。 模板参数推导需要完全匹配,不考虑隐式转换,并且如前所述,此处涉及的类型完全不同。
如果我将声明更改为variadic,那么它可以工作
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
这是有效的,因为不再涉及模板参数推断。 executeWithResultHandler
接受一个你明确指定的模板参数,并且因为lambda可以隐式转换为std::function
,所以重载解析会找到匹配项。
请注意,在第一种情况下,除了int
之外,可能还有更多的模板参数,您没有明确指定。
您可以通过将lambda显式转换为std::function
来获得原始示例。
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.