当我定义此功能时,
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; });
调用此函数时我收到以下错误:
但是,所有这些版本都可以使用:
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;}));
当我将lambda函数直接放置在表达式中而不直接创建
std::function
时,为什么c++ 11无法猜测模板类型?编辑:
根据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; });
调用它。编译器甚至可以使用new decltype关键字和新函数return type语法在某种程度上猜测返回类型。这是一个示例,该示例使用一个过滤功能和一个根据值生成键的功能将集合转换为 map :
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); });
最佳答案
问题在于lambda的性质。它们是根据标准具有固定属性集的函数对象,但不是函数。该标准确定可以将lambda转换为带有确切类型的参数的std::function<>
,如果没有状态,则将其转换为函数指针。
但这并不意味着lambda是std::function
也不是函数指针。它们是实现operator()
的唯一类型。
另一方面,类型推导只能推断出确切的类型,没有转换(const / volatile限定除外)。由于lambda不是std::function
,因此编译器无法推断出调用中的类型:filter(mySet,[](int i) { return i%2==0; });
是任何std::function<>
实例化。
与其他示例一样,在第一个示例中,您将lambda转换为函数类型,然后将其传递。编译器可以在此处推导类型,如在第三个示例中,std::function
是相同类型的右值(临时)。
如果您向模板(第二个工作示例)提供实例化类型int
,则推论不起作用,编译器将使用该类型,然后将lambda转换为适当的类型。
关于c++ - 当涉及std::function或lambda函数时,C++ 11不会推断类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31118987/