I'm trying to pass an iterator as a template parameter to a template method, but the compiler complains that:
error C2783: 'void Test::Assert(std::vector<T>::const_iterator)':
could not deduce template argument for 'T'
The code that produces the error is:
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert(myVec.cbegin());
return 0;
}
I'm guessing there is a simple way to make this work, since most of the std algorithms can deduce type from iterator.
The following code is compiled ok using clang.
The outputs:
The compiler's version:
The reason is that the form you have
T
in is a non-deduced context:Consider a simpler case to understand why:
What should
T
deduce as? It's impossible to determine. You'd have to explicitly provide the type... as something likeAssert<A>(5)
.See also What is a nondeduced context?
That's because the standard algorithms just deduce the iterator type, not the container type. For instance
std::find
is just:There is no concept of "container" here at all - it's just the iterator type that needs to be deduced. That's part of the beauty of the algorithms library.
So if what you want to do is just output the contents of the iterator, the correct function would just be:
When you call
Assert(myVec.cbegin())
,Iterator
will get deduced asstd::vector<double>::const_iterator
, which is exactly what you want.That's it - the standard library just parameterizes on the whole type of the iterator. In fact, anything that behaves like an iterator can be used (that's the main reason why iterators behave like pointers). This is called "duck typing".
What you are trying to do (restricting the function to only those types which are explicit iterators) is what C++17 concepts are about.
The standard algorithms look like this:
If they need the type of the iterator, they can use
typename std::iterator_traits<Iterator>::value_type
.What they don't do is reference a container such as
vector
in any way. Not all iterators come from containers.Try out this once.