Exercise 17.4:
/*****************************************************
* IDE: VS2010
* FILE: find_book.cpp
*****************************************************/
#include
using std::tuple; using std::make_tuple;
using std::get;
#include
using std::vector;
#include
using std::string;
#include
using std::equal_range; using std::sort;
#include
using std::accumulate; #include
using std::istream; using std::ostream; using std::cin; using std::cout; using std::endl; #include
using std::ifstream; #include "Sales_data.h" // matches has three members: an index of a store // and iterators into that store's vector typedef tuple
::size_type, \ vector
::const_iterator, \ vector
::const_iterator> matches; // files holds the transactions for every store // find_book returns a vector with an entry for each store that sold the given book vector
find_book(const vector
> &files, const string &book) { vector
ret; // initially empty // for each store find the range of matching books, if any for (auto it = files.cbegin(); it != files.cend(); ++it) { // find the range of Sales_data that have the same ISBN auto found = equal_range(it->cbegin(), it->cend(), book, compare_isbn); if (found.first != found.second) // this store has sales { ret.push_back(make_tuple(it - files.cbegin() + 1, found.first, found.second)); } } return ret; // empty if no matches found } void report_results(istream &in, ostream &os, const vector
> &files) { string s; // book to look for while (in >> s) { vector
trans = find_book(files, s); if (trans.empty()) { cout << s << " not found in any stores" << endl; continue; // get the next book to look for } for (vector
::iterator store = trans.begin(); \ store != trans.end(); ++store) // find every store with a sale { // get
returns the specified member from the tuple in store os << "store " << get<0>(*store) << " sales: " \ << accumulate(get<1>(*store), get<2>(*store), Sales_data(s)) << endl; } } } vector
build_store(const string &s) { Sales_data item; vector
ret; ifstream is(s); while (is >> item) { ret.push_back(item); } sort(ret.begin(), ret.end(), compare_isbn); return ret; } int main() { string stores[] = {"./data/store1", "./data/store2", "./data/store3", "./data/store4"}; // each element in files holds the transactions for a particular store vector
> files; for (int cnt = 0; cnt != 4; ++cnt) { files.push_back(build_store(stores[cnt])); } report_results(cin, cout, files); return 0; } /***************************************************** * IDE: VS2010 * FILE: Sales_data.h *****************************************************/ #ifndef SALES_DATA_H #define SALES_DATA_H #include
#include
class Sales_data { friend std::ostream &operator<<(std::ostream &os, const Sales_data &item); friend std::istream &operator>>(std::istream &is, Sales_data &item); friend bool operator==(const Sales_data &lhs, const Sales_data &rhs); friend bool operator!=(const Sales_data &lhs, const Sales_data &rhs); friend Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs); public: // constructors Sales_data() : units_sold(0), revenue(0.0) { } Sales_data(const std::string &s) : book_no(s), units_sold(0), revenue(0.0) { } Sales_data(const std::string &s, unsigned int n, double price) : book_no(s), units_sold(n), revenue(price * n) { } std::string isbn() const { return book_no; } Sales_data &operator+=(const Sales_data &rhs); private: std::string book_no; unsigned int units_sold; double revenue; // utility function double avg_price() const; }; // non-member Sales_data operations inline bool compare_isbn(const Sales_data &lhs, const Sales_data &rhs) { return lhs.isbn() < rhs.isbn(); } #endif /***************************************************** * IDE: VS2010 * FILE: Sales_data.cpp *****************************************************/ #include "Sales_data.h" #include
using std::string; #include
using std::istream; using std::ostream; utility function double Sales_data::avg_price() const { if (units_sold) { return revenue / units_sold; } else { return 0; } } non-member Sales_data operations ostream &operator<<(ostream &os, const Sales_data &item) { os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price(); return os; } istream &operator>>(istream &is, Sales_data &item) { double price; // no need to initialize; we'll read into price before we use it is >> item.book_no >> item.units_sold >> price; if (is) // check that the inputs succeeded { item.revenue = item.units_sold * price; } else // input failed: give the object the default state { item = Sales_data(); } return is; } bool operator==(const Sales_data &lhs, const Sales_data &rhs) { return lhs.isbn() == rhs.isbn() && lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue; } bool operator!=(const Sales_data &lhs, const Sales_data &rhs) { return !(lhs == rhs); } // member binary operator: left-hand operand is bound to the implicit this pointer // assumes that both objects refer to the same book Sales_data &Sales_data::operator+=(const Sales_data &rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } // assume that both objects refer to the same book Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; // copy data sum += rhs; return sum; }