我有一个数字列表。
我正在尝试过滤列表,只保留正数。
我试图通过传递lambda作为参数来实现。
我想知道为什么会出现函数不匹配错误。
#include <vector>
#include <algorithm>
#include <functional>
template<typename T>
std::vector<T> keep(
const std::vector<T> &original,
std::function<bool(const T&)> useful)
{
std::vector<T> out;
for(T item:original)
{
if(useful(item))
out.push_back(item);
}
return out;
}
int main()
{
std::vector<int> a={4,6,2,-5,3,-8,13,-11,27};
a=keep(a,[](const int& x)->bool{return x>0;});
for(int y:a)
{
std::cout<<y<<std::endl;
}
return 0;
}
这是错误消息:
error: no matching function for call to ‘keep(std::vector<int>&, main()::<lambda(const int&)>)’
a=keep(a,[](const int& x)->bool{return x>0;});
^
答案 0 :(得分:11)
将功能keep
更改为
template<typename T, typename Func>
std::vector<T> keep(const std::vector<T> &original,
Func useful)
{
// code as usual
}
这适用于useful
的任何一个参数:
std::function
lambda表达式构造一个未命名的prvalue临时对象,该对象具有唯一的非命名非联合非聚合类型,称为闭包类型。
这意味着两个具有相同代码的lambda将生成两个不同的类型对象。
auto f1 = [](int) { return true; };
auto f2 = [](int) { return false; };
f2 = f1; // error: no viable '='
但是,这两个都可以隐式转换为相应的std::function
类型:
std::function<bool(int)> fn = f1;
fn = f2;
但是为什么它不适合你的情况呢?这是因为模板类型扣除。将keep
更改为
template<typename T>
std::vector<T> keep(const std::vector<T> &original,
std::function<bool(const int &)> useful)
// no type deduction for std::function's template, explicitly mentioned
将使您的示例编译而不在调用者站点进行任何强制转换。
但是,尝试将其与std::function<T>
匹配不会起作用,因为模板类型扣除不考虑任何转换。模板参数推导查找精确类型匹配。隐含的转换在这个阶段并不重要。您已明确将其转换为匹配的std::function
Atomic_alarm 评论。就像约瑟夫在How to convert a lambda to an std::function using templates中所说:
模板类型推导尝试将lambda函数的类型与
std::function<T>
匹配,在这种情况下它只能做 - 这些类型不一样。模板类型推导不考虑类型之间的转换。
在替代解决方案中,会发生的事情是这样的:
auto f = [](int i) { return (i >= 0); }
此处f
的类型不是std::function
,而是推导出一些未命名的类型,就像上面的模板参数Func
一样。
如果您仍希望以std::function
方式执行此操作,请参阅使用其他模板间接执行此操作的this answer。有关详细信息,请参阅this answer和this post。