5E56,7667230284,Langler,Tyson,31.2147,0.00042117361
2B97,7586701,Oneill,Zeke,553.429,0.0074673053156065
4D75,7907252710,Nickerson,Kelly,761.612,0.010276276
9F2,6882945012,Hartenbach,Neil,47.9637,0.0006471644
Austria
480F,7187262472,Oneill,Dee,264.012,0.00356226040013
1B65,4754732628,Haney,Kim,7.33843,0.000099015948475
DA1,1954960784,Pascente,Lester,56.5452,0.0007629529
3F18,1839715659,Elsea,Chelsy,801.901,0.010819887645
Belgium
BDF,5993489554,Oneill,Meredith,283.404,0.0038239127
5AC6,6612945602,Parisienne,Biff,557.74,0.0075254727
6AD,6477082,Pennington,Lizanne,31.0807,0.0004193544
4D0E,7861652688,Sisca,Francis,704.751,0.00950906238
Bahamas
37D8,6837424208,Parisienne,Samson,396.104,0.0053445
5E98,6384069,Willis,Pam,90.4257,0.00122009564059246
1462,1288616408,Stover,Hazal,583.939,0.007878970561
5FF3,8028775718,Stromstedt,Bunk,39.8712,0.000537974
1095,3737212,Stover,Denny,3.05387,0.000041205248883
7428,2019381883,Parisienne,Shane,363.272,0.00490155
The heading of each section is a region, and every line under that heading is a seller in that region. Each comma-separated field represents the data about each seller. The first field in a line is the SELLER_ID which unfortunately was written out in hexadecimal format. The second is the PHONE_NUMBER (notice that some are missing area codes). LAST_NAME and FIRST_NAME then follow. TOTAL_SALES is the second to the last column. The last column is the decimal amount of the total sales that the seller represents for the company. You are to format the data on the terminal window so that an executive can easily interpret the trends. Sample output is given below. Australia
---------------------------------
*Last Name* *First Name* *ID* *Phone* *Sales* *Percent*
Langler Tyson 24150 766-723-0284 31.24 4.21E-02
Oneill Zeke 11159 XXX-758-6701 553.43 7.47E-01
(etc.)
5: Templates in depth
The C++ template facility goes far beyond simple "containers of T." Although the original motivation was to enable type-safe, generic containers, in modern C++, templates are also used to generate custom code and to optimize program execution through compile-time programming constructs.
In this chapter we offer a practical look at the power (and pitfalls) of programming with templates in modern C++. For a more complete analysis of template-related language issues and "gotchas," we recommend the superb book by David Vandevoorde and Nico Josuttis.[49]
Template parameters
As we illustrated in Volume 1, templates come in two flavors: function templates and class templates. Both are wholly characterized by their parameters. Each template parameter itself can represent one of the following categories of arguments:
1. Types (either built-in or user-defined)
2. Compile-time constant values (for example, integers, and pointers and references to static entities; often referred to as non-type parameters)
3. Other templates
The examples in Volume 1 all fall into the first category and are the most common. The canonical example for simple container-like templates nowadays seems to be a Stack class. Being a container, a Stack object is not concerned with the type of object it stores; the logic of holding objects is independent of the type of objects being held. For this reason you can use a type parameter to represent the contained type:.
template<class T>
class Stack {
T* data;
size_t count;
public:
void push(const T& t);
// etc.
};
You provide the actual type to be used for a particular Stack instance by means of an argument for the parameter T:
Stack<int> myStack; // A Stack of ints
The compiler then provides an int-version of Stack by substituting int for T and generating the corresponding code. The name of the class instance generated from the template in this case is Stack<int>.
Non-type template parameters
It is also possible to provide a non-type template parameter, as long as it represents an integral value that is known at compile time. You can make a fixed-size Stack, for instance, by specifying a non-type parameter to be used as the dimension for the underlying array, as follows.
template<class T, size_t N>
class Stack {
T data[N]; // Fixed capacity is N
size_t count;
public:
void push(const T& t);
// etc.
};
You must provide a compile-time constant value for the parameter N when you request an instance of this template, such as
Stack<int, 100> myFixedStack;
Because the value of N is known at compile time, the underlying array (data) can be placed on the runtime stack instead of on the free store, which can improve runtime performance by avoiding the overhead associated with dynamic memory allocation. Following the pattern mentioned earlier, the name of the class above is Stack<int, 100>. This means that each distinct value of N results in a unique class type. For example, Stack<int, 99> is a distinct class from Stack<int, 100>.
The bitset class template, discussed in detail in Chapter 7, is the only class in the standard C++ library that uses a non-type template parameter, which happens to specify the number of bits the bitset object can hold. The following random number generator example uses a bitset to track numbers so all the numbers in its range are returned in random order without repetition before starting over. This example also overloads operator( ) to produce a familiar function-call syntax.
//: C05:Urand.h
//{-bor}
// Unique randomizer
#ifndef URAND_H
#define URAND_H
#include <bitset>
#include <cstddef>
#include <cstdlib>
#include <ctime>
using std::size_t;
using std::bitset;
template<size_t UpperBound>
class Urand {
bitset<UpperBound> used;
public:
Urand() {
srand(time(0)); // randomize
}
size_t operator()(); // The "generator" function
};
template<size_t UpperBound>
inline size_t Urand<UpperBound>::operator()() {
if(used.count() == UpperBound)
used.reset(); // start over (clear bitset)
size_t newval;
while(used[newval = rand() % UpperBound])
; // Until unique value is found