There is the following code:
template<typename T>
void test(const typename std::vector<T>::iterator &i){
}
int main(int argc, char **argv)
{
std::vector<int> a;
test(a.begin());
}
The compilation will prompt an error about the inability to deduce the type 'T' for the line 'test(a.begin())'. It seems like it should be an easy inference. Is there any particular reason causing the compiler to fail in deducing it correctly?
C++ standard: 14
Compiler: Apple clang version 15.0.0
The same issue arises when using gcc. In gcc, std::vector::iterator actually corresponds to the type __gnu_cxx::__normal_iterator<pointer, vector>, where pointer is the _Vector_base<T, std::allocator>::pointer type, and vector stands for std::vector<T, std::allocator>. Therefore, expanding the type associated with std::vector::iterator results in __gnu_cxx::__normal_iterator<_Vector_base<T, std::allocator>::pointer, std::vector<T, std::allocator>>. I am struggling to understand why the passed argument type is __gnu_cxx::__normal_iterator<_Vector_base<int, std::allocator>::pointer, std::vector<int, std::allocator>>, while the function parameter type is __gnu_cxx::__normal_iterator<_Vector_base<T, std::allocator>::pointer, std::vector<T, std::allocator>>, and yet T cannot be deduced.
Correct answer: What is a non-deduced context?
The iterator is a nested type of the class template, not a class template itself. There's nothing preventing std::vector<T>::iterator
and std::vector<U>::iterator
from being the same type for T != U
.
Take this simple example:
template<typename T>
struct A
{
using iterator = int*;
};
template<typename T>
void test(typename A<T>::iterator i) {}
int main()
{
int* it = nullptr;
test(it);
}
Is it obvious in this example that T
can't be deduced? It's no different for std::vector<T>::iterator
.