Mossi
Mossi

Reputation: 36

Why is there a syntax error in my map iterator?

I wrote a template function for flipping my std::map keys and values.

#include <map>
#include <iterator>

template <typename A, typename B>
std::map<B, A> flip_map(std::map<A, B> &src)
{
    std::map<B, A> dst;
    for (std::map<A, B>::iterator it = src.begin(); it != src.end(); ++it)
    {
        dst.insert(std::pair<B, A>(it->second, it->first));
    }
    return dst;
}

VS gives me a syntax error:

unexpected token 'identifier', expected ';'

I don't know what I'm doing wrong.

Upvotes: 0

Views: 344

Answers (2)

Peter
Peter

Reputation: 36637

The reason is that std::map<A,B>::iterator is a dependent name (in rough terms, it is in a templated function, and depends on A and B which are parameters of that template). So it needs to be preceded with the typename keyword.

template <typename A, typename B>
std::map<B, A> flip_map(std::map<A, B> &src)
{
    std::map<B, A> dst;
    for (typename std::map<A, B>::iterator it = src.begin(); it != src.end(); ++it)
    {
        dst.insert(std::pair<B, A>(it->second, it->first));
    }
    return dst;
}

Additionally you would probably be better specifying src as const, and using const_iterator rather than iterator, viz

template <typename A, typename B>
std::map<B, A> flip_map(const std::map<A, B> &src)
{
    std::map<B, A> dst;
    for (typename std::map<A, B>::const_iterator it = src.begin(); it != src.end(); ++it)
    {
        dst.insert(std::pair<B, A>(it->second, it->first));
    }
    return dst;
}

or (C++11 and later), let the compiler do the type deduction for you by using auto and std::make_pair. This avoids need for the programmer to worry about dependent names.

template <typename A, typename B>
std::map<B, A> flip_map(const std::map<A, B> &src)
{
    std::map<B, A> dst;
    for (const auto &e : src)
    {
        dst.insert(std::make_pair(e.second, e.first));
    }
    return dst;
}

Upvotes: 2

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385395

GCC tells you more clearly what's wrong: you need typename there, for arcane C++ reasons.

Like this:

for (typename std::map<A, B>::iterator it = src.begin(); it != src.end(); ++it)
//   ^^^^^^^^

Further reading:


I'd instead write it like this:

#include <map>

template <typename A, typename B>
std::map<B, A> flip_map(const std::map<A, B>& src)
{
    std::map<B, A> dst;

    for (const auto& p : src)
        dst.insert(std::make_pair(p.second, p.first));

    return dst;
}

In fact, as it happens, I did; two weeks ago. :)

(You could also consider some .emplace and std::move etc, depending on what A and B are likely to be, though since you cannot move from a map key this is only ever going to be "sort of useful".)

Upvotes: 6

Related Questions