When I define this function,
template<class A>
set<A> test(const set<A>& input) {
return input;
}
I can call it using test(mySet)
elsewhere in the code without having to explicitly define the template type. However, when I use the following function:
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;
}
When I call this function using filter(mySet,[](int i) { return i%2==0; });
I get the following error:
error: no matching function for call to ‘filter(std::set&, main()::)’
However, all of these versions do work:
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;}));
Why is c++11 unable to guess the template type when I put the lambda function directly inside the expression without directly creating a std::function
?
EDIT:
Per advice of Luc Danton in the comments, here is an alternative to the function I had earlier that does not need the templates to be passed explicitly.
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;
}
This can be called by set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; });
without needing the template.
The compiler can even guess the return types to some extent, using the new decltype keyword and using the new function return type syntax. Here is an example that converts a set to a map, using one filtering function and one function that generates the keys based on the values:
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;
}
It can also be called without using the template directly, as
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
filter
is essentially equivalent to a non-generic version ofstd::copy_if
, don't you? – Jerry Coffintemplate<typename A, typename Predicate> set<A> filter(set<A> const& input, Predicate compare);
. As you've just witnessed,std::function
doesn't work to document that the passed predicate should have a signature matchingbool(A)
; there are other ways to do that. Furthermore there are other disadvantages in usingstd::function
as a function argument. – Luc Danton