Consider the following code:
template<class T>
vector<T> filter(typename vector<T>::iterator begin,
typename vector<T>::iterator end,
bool (*cond)(T a))
{
vector<T> vec;
for (typename vector<T>::iterator it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter<int>(vec.begin(), vec.end(), [](int a) {return a > 5; });
When I remove the type from the invocation of the function filter, the code does not compile, I.e. when writing
filter(vec.begin(), vec.end(), [](int a) {return a > 5; });
My question is, why? the compiler can deduce the type both from the lambda and from the iterator.
The error I get is:
Error C2784 'std::vector> filter(vector>::iterator,vector>::iterator,bool (__cdecl *)(T))': could not deduce template argument for 'bool (__cdecl *)(T)' from 'main::' example c:\users\danii\documents\visual studio 2017\projects\example\example\source.cpp 24
I couldn't find details about this problem. My guess is, the compiler can't deduce inner types? (e.g can't deduce int from vector). If this is the case, why is it? if not, what is the case? is there any way to fix it?
Another thing I encountered was using the iterator itself as a template, i.e. something like
template <class T, class iter, class cond>
vector<T> filter(iter begin, iter end, cond c)
Is it correct programming? This code looks a bit suspicious to me.
My guess is, the compiler can't deduce inner types? (e.g can't deduce int from vector).
Yes. This belongs to non-deduced contexts:
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
Note that lambda expression without capture (the 3rd argument) could convert to function pointer implicitly, but template argument deduction doesn't consider implicit conversions.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
Then, type deduction fails here.
Your idea for fixing is good idea but you don't need the template parameter T
, which can't (and don't need to) be deduced. You can change it to:
template<class iter, class cond>
auto filter(iter begin, iter end, cond c)
{
vector<typename std::iterator_traits<iter>::value_type> vec;
for (auto it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}