I have pretty simple code:
#include <iostream>
#include <list>
using namespace std;
template <typename T, typename Function>
int ex_count(typename list<T>::iterator v, typename list<T>::iterator v2, Function match)
{
int count = 0;
while(v != v2)
{
if(match(*v))
count++;
++v;
}
return count;
}
template <typename T>
class ex_eq
{
public:
ex_eq(const T &n_target = T())
{
target = n_target;
}
bool operator() (const T &a)
{
return a == target;
}
private:
T target;
};
int main()
{
list<int> v;
list<int>::iterator iv;
int value;
while (cin >> value)
v.push_back(value);
int target = *v.begin();
int N = ex_count(v.begin(), v.end(), ex_eq<int>(target));
cout << "Found " << N << " instances of " << target << "\n";
}
I recently implemented a predicate object Function match
into the int ex_count()
function, but for whatever reason this breaks the code. The only error I'm getting is that the argument 'T' cannot be inferred, for int ex_count()
, even though this was working fine using a constant instead of an object (Function match
).
I should note that I'm not looking for advice for anything other than the question I am asking. The code is overly complicated and pointless--I'm aware, but this is not my design.
What's the issue?
Error for clarity:
note: candidate template ignored: couldn't infer template argument 'T'
int ex_count(typename list<T>::iterator v, typename list<T>::iterator v2, Function match)
Edit:
I've been told that it cannot be deduced because of the ::
operator, but then why is it that this version of the code only works when using the ::
operator:
#include <iostream>
#include <list>
using namespace std;
template <typename T>
int ex_count(typename list<T>::iterator v, typename list<T>::iterator v2, T target)
{
int count = 0;
while(v != v2)
{
if(*v == target)
++count;
++v;
}
return count;
}
int main() {
list<int> v;
list<int>::iterator iv;
int value;
while (cin >> value)
v.push_back(value);
int target = *v.begin();
int N = ex_count(v.begin(), v.end(), target);
cout << "Found " << N << " instances of " << target << "\n";
}
This version does not use a function object, but instead just uses target
. However, if I try to change ex_count
arguments from list<T>::iterator
to just T
, I get the error:
note: candidate template ignored: deduced conflicting types for parameter 'T'
('std::__1::__list_iterator<int, void *>' vs. 'int')
int ex_count(T v, T v2, T target)
But it compiles just fine the way I have it written above.
So what causes this?
The template parameter T
can't be deduced because of non-deduced context.
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.
- The nested-name-specifier (everything to the left of the scope resolution operator
::
) of a type that was specified using a qualified-id:
You can specify the template argument explicitly to bypass the template argument deduction,
int N = ex_count<int>(v.begin(), v.end(), ex_eq<int>(target));
Or change the function template to specify the iterator type as the template parameter directly. (And it could be used with any iterators, including raw pointers.)
template <typename Iterator, typename Function>
int ex_count(Iterator v, Iterator v2, Function match)
{
int count = 0;
while(v != v2)
{
if(match(*v))
count++;
++v;
}
return count;
}
EDIT
For
template <typename T>
int ex_count(typename list<T>::iterator v, typename list<T>::iterator v2, T target)
Template argument deduction won't be performed on non-deduced context, then T
will be deduced only on the 3rd function argument. Given ex_count(v.begin(), v.end(), target);
T
will be deduece as int
, and v.begin()
and v.end()
match the type list<int>::iterator
, everything is fine.
For
template <typename T>
int ex_count(T v, T v2, T target)
There's no non-deduced context and T
will be deduced on all the function arguments. Given ex_count(v.begin(), v.end(), target);
, on the 1st and 2nd function arguments T
will be deduced as list<int>::iterator
, on the 3rd one it'll be deduced as int
, they are conflicting.
If you seperate the template parameters then it'll be fine.
template <typename Iterator, typename T>
int ex_count(Iterator v, Iterator v2, T target)