C++ 接受lambda的可变模板函数
我试图理解下面代码中的编译器错误。我有一个可变模板函数,它接受lambda 使用指定的类型,并且尝试调用该函数会导致模板由于不匹配而不被视为有效候选模板C++ 接受lambda的可变模板函数,c++,templates,c++11,lambda,variadic-templates,C++,Templates,C++11,Lambda,Variadic Templates,我试图理解下面代码中的编译器错误。我有一个可变模板函数,它接受lambda 使用指定的类型,并且尝试调用该函数会导致模板由于不匹配而不被视为有效候选模板 #include <functional> template<typename ... ResultTypes> void executeWithResultHandler(std::function<void (ResultTypes...)> lambda) { } int main(int argc
#include <functional>
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{
}
int main(int argc, char **argv)
{
executeWithResultHandler<int>([] (int arg) {
});
return 0;
}
#包括
模板
void executeWithResultHandler(std::function lambda)
{
}
int main(int argc,字符**argv)
{
executeWithResultHandler([](int-arg){
});
返回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.
<代码> $C++ -STD= C++ 11还原.CPP
reduce.cpp:10:5:错误:调用“executeWithResultHandler”时没有匹配的函数
executeWithResultHandler([](int-arg){
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduce.cpp:4:6:注意:已忽略候选模板:无法将“函数”与
''
void executeWithResultHandler(std::function lambda)
^
生成1个错误。
如果我将声明更改为非可变:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
模板
void executeWithResultHandler(std::function lambda)
{
}
然后它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。
我有没有遗漏什么,或者用另一种方法来实现这一点
编辑:这被错误地标记为重复,我相信-重复没有回答我提出的问题。这个问题特别与可变模板有关。请注意,当我将模板切换为非可变模板时,lambda将正确地转换为std::function类型,如预期的那样。这是无论参数的数量如何,只要不是以可变方式处理,则为true
然而,尽管期望参数包被解包为一组实际参数,并且在函数调用站点明确指定了模板参数列表,但它确实不能具体使用可变版本。在您的情况下,可变模板的问题是编译器不能现在,无论您显式指定的
int
是否是ResultTypes…
的完整列表,它都会尝试从您提供的参数中推断出可选的剩余参数,这显然是失败的。这是可变模板参数的常见陷阱,并且不限于lambda
解决方案总是意味着从编译器中删除此选项,例如
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));
}
模板
void executeWithResultHandler_impl(std::function lambda)
{
}
模板
void executeWithResultHandler(F&&lambda)
{
executeWithResultHandler_impl(std::function(lambda));
}
我之前链接为duplicate,它准确地解释了您的情况
std::function
不是lambda,它是一种可以存储任何类型可调用对象的容器。您可以将lambda分配给std::function
,但在这种情况下,必要的转换由std::function
构造函数执行
在你的例子中
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
这是因为不再涉及模板参数推导。executeWithResultHandler
只接受一个模板参数,您已经明确指定了该参数,并且由于lambda可以隐式转换为std::function
,重载解析将找到匹配项
请注意,在第一种情况下,除了int
,可能还有更多您没有明确指定的模板参数
通过显式地将lambda转换为
std::function
,可以使原始示例正常工作
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));
executeWithResultHandler(std::function([](int arg){});
lambda不是std::function
对象。它们只是带有calloperator()的函数对象
。因此,即使两个lambda具有相同的参数类型和返回类型,它们也有两种不同的类型。请参见我的相关问题:在相关问题中,我有一个包装函数,它可以使std::function对象在明确的情况下接受lambda。啊哈。我缺少的是这一点:请注意,在第一种情况下,除了int之外,可能还有更多您没有明确指定的模板参数。谢谢!
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));