17.1.2. Using a tuple to Return Multiple Values

A common use of tuple is to return multiple values from a function. For example, our bookstore might be one of several stores in a chain. Each store would have a transaction file that holds data on each book that the store recently sold. We might want to look at the sales for a given book in all the stores.

We’ll assume that we have a file of transactions for each store. Each of these per-store transaction files will contain all the transactions for each book grouped together. We’ll further assume that some other function reads these transaction files, builds a vector<Sales_data> for each store, and puts those vectors in a vector of vectors:

// each element in files holds the transactions for a particular store
vector<vector<Sales_data>> files;

We’ll write a function that will search files looking for the stores that sold a given book. For each store that has a matching transaction, we’ll create a tuple to hold the index of that store and two iterators. The index will be the position of the matching store in files. The iterators will mark the first and one past the last record for the given book in that store’s vector<Sales_data>.

A Function That Returns a tuple

We’ll start by writing the function to find a given book. This function’s arguments are the vector of vectors just described, and a string that represents the book’s ISBN. Our function will return a vector of tuples that will have an entry for each store with at least one sale for the given book:

// matches has three members: an index of a store and iterators into that store's vector
typedef tuple<vector<Sales_data>::size_type,
              vector<Sales_data>::const_iterator,
              vector<Sales_data>::const_iterator> matches;
// files holds the transactions for every store
// findBook returns a vector with an entry for each store that sold the given book
vector<matches>
findBook(const vector<vector<Sales_data>> &files,
         const string &book)
{
    vector<matches> 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, compareIsbn);
         if (found.first != found.second) // this store had sales
             // remember the index of this store and the matching range
             ret.push_back(make_tuple(it - files.cbegin(),
                                   found.first, found.second));
    }
    return ret; // empty if no matches found
}

The for loop iterates through the elements in files. Those elements are themselves vectors. Inside the for we call a library algorithm named equal_range, which operates like the associative container member of the same name (§ 11.3.5, p. 439). The first two arguments to equal_range are iterators denoting an input sequence (§ 10.1, p. 376). The third argument is a value. By default, equal_range uses the < operator to compare elements. Because Sales_data does not have a < operator, we pass a pointer to the compareIsbn function (§ 11.2.2, p. 425).

The equal_range algorithm returns a pair of iterators that denote a range of elements. If book is not found, then the iterators will be equal, indicating that the range is empty. Otherwise, the first member of the returned pair will denote the first matching transaction and second will be one past the last.

Using a tuple Returned by a Function

Once we have built our vector of stores with matching transactions, we need to process these transactions. In this program, we’ll report the total sales results for each store that has a matching sale:

void reportResults(istream &in, ostream &os,
                   const vector<vector<Sales_data>> &files)
{
    string s;  // book to look for
    while (in >> s) {
        auto trans = findBook(files, s); // stores that sold this book
        if (trans.empty()) {
            cout << s << " not found in any stores" << endl;
            continue;  // get the next book to look for
        }
        for (const auto &store : trans)  // for every store with a sale
            // get<n> 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;
    }
}

The while loop repeatedly reads the istream named in to get the next book to process. We call findBook to see if s is present, and assign the results to trans. We use auto to simplify writing the type of trans, which is a vector of tuples.

If trans is empty, there were no sales for s. In this case, we print a message and return to the while to get the next book to look for.

The for loop binds store to each element in trans. Because we don’t intend to change the elements in trans, we declare store as a reference to const. We use get to print the relevant data: get<0> is the index of the corresponding store, get<1> is the iterator denoting the first transaction, and get<2> is the iterator one past the last.

Because Sales_data defines the addition operator (§ 14.3, p. 560), we can use the library accumulate algorithm (§ 10.2.1, p. 379) to sum the transactions. We pass a Sales_data object initialized by the Sales_data constructor that takes a string7.1.4, p. 264) as the starting point for the summation. That constructor initializes the bookNo member from the given string and the units_sold and revenue members to zero.


Exercises Section 17.1.2

Exercise 17.4: Write and test your own version of the findBook function.

Exercise 17.5: Rewrite findBook to return a pair that holds an index and a pair of iterators.

Exercise 17.6: Rewrite findBook so that it does not use tuple or pair.

Exercise 17.7: Explain which version of findBook you prefer and why.

Exercise 17.8: What would happen if we passed Sales_data() as the third parameter to accumulate in the last code example in this section?


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset