[英]How can I pass a lambda (c++11) into a templated function?
我正在使用gcc 4.6.2中的lambda函数,并希望实现模板化的“map”函数,如下所示:
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, const std::function<B(A)> f) {
std::vector<B> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
这不起作用,因为测试代码:
int main(int argc, char **argv) {
std::vector<int> list;
list.push_back(10);
list.push_back(20);
list.push_back(50);
std::vector<int> transformed = map(list, [](int x) -> int { return x + 1; });
std::for_each(begin(transformed), end(transformed), [](int x) { printf("-> %d\n", x); });
return 0;
}
给出了这个错误:
test.cpp:49:80: error: no matching function for call to ‘map(std::vector<int>&, main(int, char**)::<lambda(int)>)’
test.cpp:49:80: note: candidate is:
test.cpp:6:49: note: template<class A, class B> std::vector<B> map(const std::vector<A>&, std::function<B(A)>)
如果我删除模板,并直接使用向量,它编译很好:
std::vector<int> map(const std::vector<int>& orig, const std::function<int(int)> f) {
std::vector<int> rv;
rv.resize(orig.size());
std::transform(begin(orig), end(orig), begin(rv), f);
return rv;
}
所以我定义模板的方式一定是个问题。
有没有人遇到过这个? 我知道lambdas是非常新的。
您不需要使用std :: function。 只需将谓词参数设为模板值即可。 例如,
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {
std :: function <>作为成员值类型或用于定义非模板化代码更有用。
我也在处理lambdas,我注意到你可以在函数定义的参数列表中声明一个函数指针,当你调用该函数时,如果它与函数原型匹配,你可以传递一个lambda表达式作为参数。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T,typename C>
struct map {
typedef C (*F)(const T&);
std::vector<C> rv;
map () {}
map (const std::vector<T>& o,F f) {
rv.resize(o.size());
std::transform (o.begin(),o.end(),rv.begin(),f);
}
~map () {}
operator std::vector<C> () const {
return rv;
}
};
int main () {
std::vector<int> asd(5,12);
std::vector<char> transformed=map<int,char>(asd,[](const int& x)->char {return x+1;});
std::copy (transformed.begin(),transformed.end(),std::ostream_iterator<int>(std::cout," "));
}
问题是编译器无法弄清楚要用于B的内容。为了确定该类型它想要使用函数<>你传入f
,但是你没有传递一个std :: function <>直。 你传递了你期望用来构造函数<>的东西。 并且为了进行隐式构造,它需要知道参数的类型。 所以你有这个循环依赖,其中参数的类型取决于你传入的内容,但传入的内容取决于参数的类型。
您可以通过指定模板参数来破坏此循环依赖关系,例如map_<int,int>(list, [](int x) -> char { return x + 1; });
(虽然我看到仿函数实际上返回一个char,而不是一个int,所以如果类型推导在这里工作,你将得到一个vector<char>
,当你分配结果时,它不能转换为vector<int>
transformed
)
但是正如已经指出的,通常模板将仿函数仅仅作为普通的模板类型:
template<typename A,typename Func>
auto map_(const std::vector<A>& orig, Func f) -> std::vector<decltype(f(A()))> {
std::vector<decltype(f(A()))> rv;
/*...*/
}
(我们使用尾部返回类型,因为我们需要在返回类型中使用表达式f
,除非之后返回类型,否则该表达式不可用。)
这允许模板直接推导出仿函数类型并避免任何类型转换,并且最好允许优化。
在这些函数中使用迭代器作为参数也是习惯,在这种情况下,你的函数只是std :: transform的包装器,所以你可以直接使用它。 我不确定在特殊版本中特别处理矢量有很多价值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.