Я пытаюсь найти сумму элементов в наборе, и мне было интересно, как найти хорошие способы ее найти.
Я построил два класса, один с именем Customer, а другой с Item, я хочу написать функцию, которая будет вычислять общую сумму, которую клиент должен заплатить за свои продукты, перечисленные в std :: set из типа Item.
Вот декларация моего набора:
set<Item> _items;
Класс предмета:
private:
string _name;
string _serialNumber; //consists of 5 numbers
int _count=0; //default is 1, can never be less than 1!
double _unitPrice; //always bigger than 0!
Функция в классе Item для суммирования цены товара:
double Item :: totalPrice() const
{
return _count*_unitPrice;
}
Вот функция, которую я пытаюсь написать, которая суммирует все мои элементы:
#include <numeric>
#include "Customer.h"double Customer::totalSum() const
{
double sum = std::accumulate(_items.begin(), _items.end(), 0.0);
return sum;
}
Но я получаю эту ошибку: error C2893: Failed to specialize function template 'unknown-type std::plus<void>::operator ()(_Ty1 &&,_Ty2 &&) const'
Важное замечание: класс Customer уже включает заголовок Item.
РЕДАКТИРОВАТЬ: Добавлена информация об элементе класса.
Если предположить, Item
это что-то вроде этого:
struct Item {
double price;
};
Тогда вы можете использовать следующее:
auto add_item_price = [](double sum, const Item& item) {
return sum + item.price;
};
double sum = std::accumulate(_items.begin(), _items.end(), 0.0, add_item_price);
Вот функциональная демоверсия.
Объяснение:
std::accumulate
позволяет вам предоставить функцию / функтор, который будет выполнять накопление. Код, который я разместил, использует лямбда-функция сделать накопление. Если вы не используете C ++ 11, вы можете использовать обычную функцию вместо лямбда-функции.
Избегайте перегрузок operator+
за Item
. Добавление двух Item
с не имеет особого смысла.
Эта ошибка обычно возникает, когда компилятор не знает, как накапливать ваш тип. т.е. надо знать как добавить Item
тип.
Таким образом, вы должны перегрузить +
оператор в вашем Item
учебный класс.
Или вы должны предоставить 4-й аргумент binary_op
Вам необходимо указать operator+()
для тебя Item
тип.
Также обратите внимание, что вам нужно operator<()
класть Item
объекты в std::set
потому что это ассоциативный контейнер, который должен уметь сравнивать его объекты:
#include <iostream>
#include <set>
#include <algorithm>
struct Item
{
Item(double price) : m_price(price) {}
friend double operator+(const Item &lhs, const Item &rhs)
{
return lhs.m_price + rhs.m_price;
}
friend double operator<(const Item &lhs, const Item &rhs)
{
return lhs.m_price < rhs.m_price;
}
double m_price;
};
int main ()
{
std::set<Item> _items;
_items.insert( Item(10) );
_items.insert( Item(20) );
double sum = std::accumulate(_items.begin(), _items.end(), 0.0);
std::cout << "Sum = " << sum << std::endl;
return 0;
}
Выход:
Sum = 30
Я единственный, кто думал об использовании простого цикла?
auto sum = 0.0;
for (const auto& item : items){
sum += item.m_price;
}
Вы можете спросить, что проще?
Ошибка, которую вы получаете от компилятора, не зная, как добавить два объекта типа Item
вместе во время звонка std::accumulate
.
Самое простое решение — использовать перегрузку std::accumulate
это принимает четвертый параметр, который определяет лямбда-функтор, который будет использоваться вместо значения по умолчанию std::plus<T>
функциональный объект.
double Customer::totalSum() const {
return std::accumulate(_items.begin(), _items.end(), 0.0,
[] (double previousValue, const auto& item) { // Called for every element.
return previousValue + item.totalPrice();
});
}
Другое решение заключается в создании настраиваемой перегрузки для operator+
это может добавить два Item
объекты.
double operator+(const Item& lhs, const Item& rhs) {
return lhs.totalPrice() + rhs.totalPrice();
}
Это может, однако, быть немного запутанным, поскольку класс Item
имеет несколько членов, которые являются числами, и не очевидно, как должно происходить добавление. Будьте особенно внимательны при перегрузке арифметических операторов.