【发布时间】:2012-04-17 09:50:58
【问题描述】:
当我定义这个函数时,
template<class A>
set<A> test(const set<A>& input) {
return input;
}
我可以在代码的其他地方使用test(mySet) 调用它,而无需显式定义模板类型。但是,当我使用以下功能时:
template<class A>
set<A> filter(const set<A>& input,function<bool(A)> compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
当我使用filter(mySet,[](int i) { return i%2==0; }); 调用此函数时
我收到以下错误:
错误:没有匹配的函数调用'filter(std::set&, main()::)'
但是,所有这些版本都可以工作:
std::function<bool(int)> func = [](int i) { return i%2 ==0; };
set<int> myNewSet = filter(mySet,func);
set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; });
set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;}));
为什么不直接创建std::function,直接把lambda函数放在表达式里面,c++11就猜不出模板类型?
编辑:
根据 cmets 中 Luc Danton 的建议,这是我之前使用的不需要显式传递模板的函数的替代方法。
template<class A,class CompareFunction>
set<A> filter(const set<A>& input,CompareFunction compare) {
set<A> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret.insert(*it);
}
}
return ret;
}
这可以通过set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; }); 调用而不需要模板。
编译器甚至可以在某种程度上猜测返回类型,使用新的 decltype 关键字和使用新的函数返回类型语法。这是一个将集合转换为映射的示例,使用一个过滤函数和一个基于值生成键的函数:
template<class Value,class CompareType,class IndexType>
auto filter(const set<Value>& input,CompareType compare,IndexType index) -> map<decltype(index(*(input.begin()))),Value> {
map<decltype(index(*(input.begin()))),Value> ret;
for(auto it = input.begin(); it != input.end(); it++) {
if(compare(*it)) {
ret[index(*it)] = *it;
}
}
return ret;
}
也可以不直接使用模板调用,如
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
【问题讨论】:
-
与您的问题无关,但您确实意识到您的
filter本质上等同于std::copy_if的非通用版本,不是吗? -
啊,我不知道 std::copy_if,谢谢你指出这一点。但是,这是一组更大的 4 个函数的一部分,其中一个函数在过滤时转换 set => map,我看不到使用 copy_if 实现它并允许用户使用集合中的值生成键的方法。为了使用的一致性,我选择这样做。
-
为了记录,如果你想接受一个仿函数,通常习惯用它作为一个通用的模板参数,即
template<typename A, typename Predicate> set<A> filter(set<A> const& input, Predicate compare);。正如您所看到的,std::function无法记录传递的谓词应该具有匹配bool(A)的签名;还有其他方法可以做到这一点。此外,使用std::function作为函数参数还有其他个缺点。
标签: c++ templates lambda c++11