Adding all values of map using std::accumulate

Daqs picture Daqs · Jul 11, 2015 · Viewed 12.1k times · Source

I am simply trying to add values of a map defined in the program below:

std::map<int, int> floor_plan;

const size_t distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0);

std::cout << "Total: " << distance;

I get the following error:

Error C2893: Failed to specialize function template 'unknown-type std::plus::operator ()(_Ty1 &&,_Ty2 &&) const'

Answer

Piotr Skotnicki picture Piotr Skotnicki · Jul 11, 2015

std::begin(floor_plan) gives you an iterator pointing at std::map<int, int>::value_type which is std::pair<const int, int>. Since there is no operator+ defined for this pair type and an integer, your code fails to compile.

Option #1

If you want to sum up all the mapped values from floor_plan, you'd need to provide your own binary operator that is able to extract the second element of a dereferenced iterator passed in:

std::accumulate(std::begin(floor_plan)
              , std::end(floor_plan)
              , 0
              , [] (int value, const std::map<int, int>::value_type& p)
                   { return value + p.second; }
               );

DEMO 1

Option #2

Alternatively, you could exploit the Boost.Iterator library to extract the second element of a pair on the fly with boost::make_transform_iterator:

#include <boost/iterator/transform_iterator.hpp>
#include <functional>

auto second = std::mem_fn(&std::map<int, int>::value_type::second);
std::accumulate(boost::make_transform_iterator(std::begin(floor_plan), second)
              , boost::make_transform_iterator(std::end(floor_plan), second)
              , 0);

DEMO 2

Option #3

Another approach is to use the Boost.Range library along with its own implementation of the accumulate algorithm:

#include <boost/range/numeric.hpp>
#include <boost/range/adaptor/map.hpp>

boost::accumulate(floor_plan | boost::adaptors::map_values, 0);

DEMO 3