5

I had created a class inheriting std::map and trying to get value at particular index using an method.

#define MYAPI_EXPORTS
#ifdef MYAPI_EXPORTS  
#define MY_API __declspec(dllexport)
#else  
#define MY_API __declspec(dllimport)   
#endif

    template<class _Value>
    class MY_API MyDictionary : public std::map<std::string, _Value>
    {
        _Value GetItem(int index)
        {
            std::map<std::string, _Value>::iterator itr = this->begin(); //compile error at this line

            int c = 0;
            while (c < index)
            {
                itr++;
                c++;
            }
            return itr->second;
        }
    };

'std::map::iterator itr' this line shows error while compiling.

the errors are

error C2760: syntax error: unexpected token 'identifier', expected ';'
error C7510: 'iterator': use of dependent type name must be prefixed with 'typename'

It seems like iterator type is not defined in compile time. Is there any solution to fix this?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
S.Frank Richarrd
  • 488
  • 1
  • 3
  • 15

3 Answers3

12

You can fix it in such ways:

typename std::map<std::string, _Value>::iterator itr = this->begin();

or

auto itr = this->begin();
zcorvid
  • 386
  • 1
  • 11
5

The error message tells you exactly what you can do:

   typename std::map<std::string, _Value>::iterator itr = this->begin();
// ^^^^^^^^^

… but not why you have to.

In short, this is a quirk of C++ relating to templates and so-called "dependent names". Because _Value is a template parameter, and because template specialisation exists, C++ can't know for sure that std::map<std::string, _Value> has a member type iterator until a little later in the parsing process. As such, your declaration is ill-formed because the compiler can't quite see it as a declaration even if it squints. typename says "this is going to be a type, I promise" and then everything's fine (as long as it does turn out to be a type!).

You may think that this should be C++'s problem, rather than yours, and you'd probably be right, but that's just the way it is. You can search for more information on this or just take it for granted that when the compiler tells you to write typename, you write typename.

Alternatively, make your code nicer and solve the problem at the same time, by using auto instead:

auto itr = this->begin();

By the way, your code suggests that you're using the wrong container, GetItem should be const, you should use cbegin() not begin() (though this is sort of done for you if you follow the const suggestion), and std::advance already exists…

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

To fix the error, you can either follow the hint given by the compiler or change the line into

auto itr = this->begin();

While overusing auto is questionable, it's usually considered ok for iterator types; return types of begin() and end() member functions are common (and sometimes complicated) enough to not type the exact type.

A further side note: GetItem can use a const_iterator, too, and hence auto itr = this->cbegin(); would be an improvement.

lubgr
  • 37,368
  • 3
  • 66
  • 117