Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::for_each on a map call the copy constructor? [duplicate]

I have the following simple example, in which I want to call std::for_each on a collection of objects that are non-copyable:

class A {
public:
    A() : x(0) {}
    A(const A&) = delete;

private:
    int x;
};

void func() {
    std::vector<A> v(10);
    std::map<int, A> m;

    // works as expected
    std::for_each(begin(v), end(v), [](const A& a) { /* do nothing */ });

    // error calling copy constructor
    std::for_each(begin(m), end(m), [](const std::pair<int, A>& a) { /* do nothing */ });
}

If I put everything into a std::vector, it works as I expected, but when using a std::map, suddenly std::for_each wants to call the (deleted) copy constructor. Why? I would have assumed that I simply get a reference to the pair that is saved in the map, without any necessary copies.

like image 859
fschoenm Avatar asked Jan 09 '14 09:01

fschoenm


1 Answers

The problem is that std::map has a std::pair<const Key, Value> as its internal value type. Rather than explicitly specifying this, Standard Library containers allow you to extract this from the container type:

In C++11 do (same as in C++98, but you would have to use a function object rather than a lambda inside for_each, and also use typedef instead of using =):

using value_type = std::map<int, A>::value_type;
std::for_each(begin(m), end(m), [](value_type const& a) { /* do nothing */ });

In C++14 do:

std::for_each(begin(m), end(m), [](auto const& a) { /* do nothing */ });

The use of auto inside the lambda is supported by Clang 3.4, Visual Studio 2013 November CTP, and GCC 4.9.

like image 135
TemplateRex Avatar answered Sep 28 '22 14:09

TemplateRex