19

我只是想添加下面程序中定义的地图的值:

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;

我收到以下错误:

错误 C2893:无法专门化函数模板 'unknown-type std::plus::operator ()(_Ty1 &&,_Ty2 &&) const'

4

3 回答 3

34

std::begin(floor_plan)给你一个指向std::map<int, int>::value_typewhich is的迭代器std::pair<const int, int>。由于没有operator+为此对类型和整数定义,您的代码无法编译。

选项1

如果您想对 中的所有映射值求和floor_plan,您需要提供自己的二元运算符,该运算符能够提取传入的取消引用迭代器的第二个元素:

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

演示 1

选项#2

或者,您可以利用Boost.Iterator库动态提取对的第二个元素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);

演示 2

选项#3

另一种方法是使用Boost.Range库以及它自己的accumulate算法实现:

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

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

演示 3

于 2015-07-11T08:51:19.607 回答
4

Piotr S. 的答案是正确的,但如果这不是一次性任务,您最好为此类任务制作一个简单方便的函子:

struct AddValues
{
  template<class Value, class Pair> 
  Value operator()(Value value, const Pair& pair) const
  {
    return value + pair.second;
  }
};

const size_t distance = std::accumulate(plan.begin(), plan.end(), 0, AddValues());

感谢模板化,你可以在你的代码operator()中使用这个函子。map这很像透明比较器,但这是透明的“求和器”。

于 2015-07-11T10:10:26.103 回答
1

我不仅会告诉你它是如何工作的。

accumulate可能的实现如下(因为我们可以从一个基值求和,所以有一个init值):

template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init,
             BinaryOperation op)
{
    for (; first != last; ++first) {
        init = op(std::move(init), *first); // std::move since C++20
    }
    return init;
}

所以当我们想要得到sum/productavector时,它可能是这样的:

vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 1);

cout<<"vec: ";// output vec
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(cout, ", "));
// vec: 1, 2, 3, 4, 5,

cout<<"\n vec sum is: "<<accumulate(vec.begin(), vec.end(), 0)<<endl;
// vec sum is: 15

cout<<"vec product is: "<<accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>())<<endl;
// vec product is: 120

至于std::map,您想对 an 的第二个值求和,因此您必须在 mapmap中获取每个值。second item所以你应该进去value_typemap然后得到第二个项目。value_typeinmap定义如下:

template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
    // using re_tree to sort
    typedef Key    key_type;

    // rb_tree value type
    typedef std::pair<key_type, value_type> value_type;
};

例如,获取所有second/first值的总和:

typedef map<string, int> IdPrice;
IdPrice idPrice = {{"001", 100}, {"002", 300}, {"003", 500}};

int sum = accumulate(idPrice.begin(), idPrice.end(), 0, [](int v, const IdPrice::value_type& pair){
    return v + pair.second;
    // if we want to sum the first item, change it to 
    // return v + pair.first;
});
cout<<"price sum is: "<<sum<<endl; // price sum is: 900

v上面的 paralambda funtion存储了 tmp 总和,初始值为 0。

于 2018-09-30T10:28:21.790 回答