2016-01-16 4 views
2

Я пытаюсь найти сумму элементов в наборе, и мне было интересно, какие хорошие способы ее найти. Я построил два класса, один из которых называется Customer, и один под названием Item, я хочу написать функцию, которая будет вычислять общий платеж, который клиент должен заплатить за свои продукты, перечисленные в std :: set, из типа Item. Вот decleration моего набора:Как суммировать элементы std :: set

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! 

Функция в классе п суммировать цену товара:

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'

Improtant примечание: Класс Customer уже включает в себя заголовок пункта.

EDIT: Добавлена ​​информация об элементе класса.

+0

Что такое 'Товар'? Если это класс, а не просто «typedef double» или аналогичный, вам нужно сообщить компилятору, как добавить два из них вместе. –

+0

Вы должны сказать, как добавить «Предмет» друг к другу –

+0

Это класс, я уверен, что упомянул об этом выше. – Jokerah

ответ

0

Эта ошибка обычно возникает, когда компилятор не знает, как скопировать ваш тип. i.e Он должен знать, как добавить Item. Так что вы должны перегрузить + оператора в вашем классе Item.
Или вы должны поставить 4-ый рассуждение binary_op

3

Предполагая 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); 

Here's a functional demo.

Объяснение:

std::accumulate позволяет обеспечить функцию/функтор, который будет делать накопления. Код, который я опубликовал, использует lambda function, чтобы выполнить накопление. Если вы не используете C++ 11, вы можете использовать регулярную функцию вместо лямбда-функции.

Избегайте перегрузки operator+ для Item. Добавление двух Item s не имеет большого смысла.

+0

Существует проблема с суммой возврата строки + item.price, потому что цена является частной в моем классе, поэтому я не могу получить доступ к ней за ее пределами. – Jokerah

+0

@Jokerah: Затем вызовите 'item.totalPrice()' или любой другой метод, который вы будет использовать, чтобы нормально получить цену «Предмет». Код не требует, чтобы вы буквально писали 'item.price'. Вы можете заменить 'item.price' любым подходящим способом, чтобы получить цену предмета. – Cornstalks

0

Вам необходимо указать 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 
+0

Я реализовал оператор < and >, а также оператор == :) – Jokerah

+0

Перегрузка 'operator +' звучит подозрительно. Кроме того, перегрузка 'operator <', вероятно, не является идеальным выбором (стоит ли сравнивать цену? Count? Name? Something else?). 'std :: set' позволяет вам предоставить функтор для сравнения и сортировки элементов; используйте это вместо того, чтобы вводить 'operator <' (поскольку на самом деле не совсем ясно, что следует сравнивать с оператором <'). – Cornstalks

+0

@ Корнистовы: это звучит разумно; Однако перегрузочные операторы были самым простым способом иметь пример выполнения. –

0

Ошибка, полученная от компилятора, не зная, как добавить два объекта типа 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 имеет несколько пользователей, которые являются числами, и это не очевидно, как дополнение должно иметь место. Будьте осторожны при перегрузке арифметических операторов.

0

Я единственный, кто думал об использовании простой петли?

auto sum = 0.0; 
for (const auto& item : items){ 
    sum += item.m_price; 
} 

Вы можете попросить более простой, чем это?