简体   繁体   中英

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.

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".)

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM