C++ iterating std::accumulate() over a map of unique_ptr: no known conversion

Viewed 222

This is probably a case of Friday afternoon blindness... why is the accumulation over the map not working. It hands me a compile error

main.cpp:35:80: note:   no known conversion for argument 2 from ‘std::pair, std::unique_ptr >’ to ‘const std::pair, std::unique_ptr >&’

What is wrong with this cast?

#include <vector>
#include <map>
#include <memory>
#include <numeric>
#include <iostream>

using namespace std;

struct Foo
{
    long bar() const {return 1;}
};


int main()
{

    std::vector<std::unique_ptr<Foo>> v;

    auto baz = [](long x, const std::unique_ptr<Foo>& p){return x + p->bar();};

    std::accumulate(v.begin(), v.end(), 0L, baz);



    std::map<std::string, std::unique_ptr<Foo>> m;

    auto bam = [](long x, const std::pair<std::string, std::unique_ptr<Foo>>& p) {
        return x + p.second->bar();
    };

    std::accumulate(m.begin(), m.end(), 0L, bam);


    return 0;
}

1 Answers

The value_type of std::map is std::pair<const Key, T>; note that the key is qualified as const. So for std::map<std::string, std::unique_ptr<Foo>> the value_type is std::pair<const std::string, std::unique_ptr<Foo>>, but not std::pair<std::string, std::unique_ptr<Foo>>. Because of std::unique_ptr, a temporary std::pair<const std::string, std::unique_ptr<Foo>> can't be copy-constructed from std::pair<std::string, std::unique_ptr<Foo>> (and bound to parameter p with type of reference to const).

You can change the lambda's parameter's type to match the value_type exactly, then the argument could be bound directly.

auto bam = [](long x, const std::pair<const std::string, std::unique_ptr<Foo>>& p) {
//                                    ^^^^^
    return x + p.second->bar();
};

You can also use member types of std::map like value_type or const_reference.

auto bam = [](long x, const std::map<std::string, std::unique_ptr<Foo>>::value_type& p) {
    return x + p.second->bar();
};

auto bam = [](long x, std::map<std::string, std::unique_ptr<Foo>>::const_reference p) {
    return x + p.second->bar();
};
Related