我试图理解我在下面的代码中遇到的编译器错误。我有一个接受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类型,如预期的那样。无论参数的数量是多少都是如此,只要不以可变方式处理它。
但是,它确实不使用可变参数版本,尽管期望将参数包解包为一组实际参数,并且在函数中显式指定模板参数列表呼叫网站。
答案 0 :(得分:3)
您的情况下可变参数模板的问题是编译器不知道您明确指定的int
是否是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));
}
答案 1 :(得分:3)
The question我以前链接过,因为副本会准确解释您的情况。
std::function
不一个lambda,它是可以存储任何类型的可调用对象的容器类型。您可以将lambda分配给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) {}));