std::basic_string::iterator as a function argument

26 Views Asked by At

I am having difficulty understanding why the following piece of code does not compile (MSVC 2022, C++20 mode):

#include <string>
template <typename T>
void d1(std::basic_string<T>::iterator x)
{
}

MSVC compiler gives very cryptic collection of 4 error messages and two warnings for the same location:

error C2182: 'd1': this use of 'void' is not valid
warning C4346: 'std::basic_string<_Elem,std::char_traits<_Elem>,std::allocator<_Ty>>::iterator': dependent name is not a type message : prefix with 'typename' to indicate a type
error C2146: syntax error: missing ')' before identifier 'x'
error C2143: syntax error: missing ';' before '{'
error C2447: '{': missing function header (old-style formal list?)

The only thing here that at least gives some sort of a hint is warning C4345, so I tried this and it fixed the problem:

#include <string>
template <typename T>
void d2(typename std::basic_string<T>::iterator x)
{
}

But I don't want to use this solution mindlessly and now I would like to learn what underlying C++ mechanism requires the use of the typename keyword in order to compile the code successfully.

In my attempt to understand this, I tried to construct other code examples to see at which point the error occurs, and this is what I got:

//iterator of std::string class is passed as an argument, compiles fine
void a1(std::string::iterator x)
{
}

//iterator of std::basic_string<char> class is passed as an argument, compiles fine
void b1(std::basic_string<char>::iterator x)
{
}

//std::basic_string<> is passed as an argument into template function, compiles fine
template <typename T>
void c1(std::basic_string<T> x)
{
}

//iterator of std::basic_string<> is passed as an argument into template function, fails to compile
template <typename T>
void d1(std::basic_string<T>::iterator x)
{
}

//iterator of std::basic_string<> is passed as an argument into template function (prefixed by typename keyword), compiles fine
template <typename T>
void d2(typename std::basic_string<T>::iterator x)
{
}

Basically everything works fine without the use of typename keyword until I try to do both of the following:

  1. Use a template
  2. Pass an iterator

Separately these two things are acceptable for the compiler, but a combination of them makes the compiler choke.

So it is a mystery to me why functions a1, b1, c1 compile fine without the use a a typename keyword, and only functions d1/d2 require the typename keyword as an argument prefix.

0

There are 0 best solutions below