我正在使用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;
}
所以我定义模板的方式一定是个问题。
有没有人遇到过这个?我知道lambda是非常新的。
答案 0 :(得分:2)
您不需要使用std :: function。只需将谓词参数设为模板值即可。例如,
template<typename A, typename B> std::vector<B> map(const std::vector<A>& orig, B f) {
的std ::功能&LT;&GT;作为成员值类型或用于定义非模板化代码更有用。
答案 1 :(得分:0)
我也正在使用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," "));
}
答案 2 :(得分:0)
问题在于编译器无法确定要用于B的内容。为了确定该类型,它想要使用函数&lt;&gt;你传递了f
,但你没有传递std :: function&lt;&gt;直。您传递了您希望用于构造函数&lt;&gt;的内容。并且为了进行隐式构造,它需要知道参数的类型。所以你有这个循环依赖,其中参数的类型取决于你传入的内容,但传入的内容取决于参数的类型。
您可以通过指定模板参数(例如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的包装器,所以你可以直接使用它。我不确定特殊版本中是否有很多值,特别是处理矢量。