Multiple functions may be nearly identical, differing only in their data types, as below.
// Find the minimum of three numbers
int TripleMin(int item1, int item2, int item3) {
int minVal;
minVal = item1;
if(item2 < minVal) {
minVal = item2;
}
if(item3 < minVal) {
minVal = item3;
}
return minVal;
}
// Find the minimum of three "chars"
char TripleMin(char item1, char item2, char item3) {
char minVal;
minVal = item1;
if(item2 < minVal) {
minVal = item2;
}
if(item3 < minVal) {
minVal = item3;
}
return minVal;
}
Writing and maintaining redundant functions that only differ by data type can be time consuming and error prone. C++ supports a better approach.
A function template is a function having a special type parameter that may be used in place of types in the function.
#include <iostream>
#include <string>
using namespace std;
template<typename MyType>
MyType TripleMin(MyType item1, MyType item2, MyType item3) {
MyType minVal = item1; // Holds min item value, init to first item
if(item2 < minVal) {
minVal = item2;
}
if(item3 < minVal) {
minVal = item3;
}
return minVal;
}
int main() {
int num1 = 55; // Test case 1, item1
int num2 = 99; // Test case 1, item2
int num3 = 66; // Test case 1, item3
char let1 = 'a'; // Test case 2, item1
char let2 = 'b'; // Test case 2, item2
char let3 = 'c'; // Test case 2, item3
string str1 = "aaa"; // Test case 3, item1
string str2 = "bbb"; // Test case 3, item2
string str3 = "ccc"; // Test case 3, item3
// Try TripleMin function with ints
cout << "Min: " << TripleMin(num1, num2, num3) << endl;
// Try TripleMin function with chars
cout << "Min: " << TripleMin(let1, let2, let3) << endl;
// Try TripleMin function with strings
cout << "Min: " << TripleMin(str1, str2, str3) << endl;
return 0;
}
The function return type is preceded by template<typename TheType>
, where TheType
can be any identifier. That type is known as a template parameter and can be used throughout the function for any parameter types, return types, or local variable types. The identifier may be various items such as an int, double, char, or string, or a pointer or reference, or even another template parameter.
The compiler automatically generates a unique function definition for each type appearing in function calls to the function template. Thus, the above program would create three TripleMin function definitions using int, char, and string. The programmer never sees those function definitions.
template<typename MyType>
_____<3> MyType x, MyType y, MyType z) {
return (x + y + z);
}
Answer: MyType. This function attempts to average i, j, and k of MyType, so should return the same type.
template<typename ____>
T TripleMin(T item1, T item2, T item3) { ... }
Answer: T. T is the identifier being used as the typename for this function template.
TripleMin(i, j, k)
but those arguments are of type long long
?Answer: The compiler creates a function with long long types and calls that function. Function template support various types.
TripleMin(i, j, k)
but those arguments are of type string
?Answer: String is just another type, so the function will compare strings. Function templates support various types, including strings.
TripleMin(i, j, z)
where i
and j
are ints, but z
is a string?Answer: The compiler will generate an error, because TheType must be the same for all three arguments. TheType is just one type. The compiler doesn't know how to generate a function for two ints and a string.
Programmers optimally may explicitly specify the type as a special argument, as in TripleMin<int>(num1, num2, num3);
template<typename T1, typename T2>
ReturnType FunctionName(Parameters) {
...
}
Earlier versions of C++ used the word "class" rather than "typename". Though misleading (the type need not be a class, but can be int or double, for example), the word class is still allowed for backwards compatibility, and much existing C++ code uses that word.
This program currently fails to compile. Modify TripleMin() so that item1 can be of a different type than item2 and item3.
Answer:
#include <iostream>
using namespace std;
template<typename TheType, TheType2>
TheType TripleMin(TheType item1, TheType2 item2, TheType2 item3) {
TheType minVal = item1; // Holds min item value, init to first item
if (item2 < minVal) {
minVal = item2;
}
if (item3 < minVal) {
minVal = item3;
}
return minVal;
}
int main() {
int num1;
int num2;
int num3;
double dbl1;
num1 = 55;
num2 = 99;
num3 = 66;
dbl1 = 12.5;
cout << "Items: " << num1 << " " << num2 << " " << num3 << endl;
cout << "Min: " << TripleMin(num1, num2, num3) << endl << endl;
cout << "Items: " << dbl1 << " " << num2 << " " << num3 << endl;
cout << "Min: " << TripleMin(dbl1, num2, num3) << endl << endl;
return 0;
}
Define a generic function called CheckOrder() that checks if four items are in ascending, neither, or descending order. The function should return -1 if the items are in ascending order, 0 if the items are unordered, and 1 if the items are in descending order.
The program reads four items from input and outputs if the items are ordered. The items can be different types, including integers, strings, characters, or doubles.
Ex. If the input is
bat hat mat sat
63.2 96.5 100.1 123.5
the output is
Order: -1
Order: -1
Complete the following code:
Answer:
#include <string>
#include <iostream>
using namespace std;
template<typename T>
int CheckOrder(T item1, T item2, T item3, T item4) {
// Check the order of the input: return -1 for ascending,
// 0 for neither, 1 for descending
if ((item1 < item2)
&& (item2 < item3)
&& (item3 < item4)) {
return -1;
}
else if ((item1 > item2)
&& (item2 > item3)
&& (item3 > item4)) {
return 1;
}
else {
return 0;
}
}
int main() {
// Read in four strings
string stringArg1, stringArg2, stringArg3, stringArg4;
cin >> stringArg1;
cin >> stringArg2;
cin >> stringArg3;
cin >> stringArg4;
// Check order of four strings
cout << "Order: " << CheckOrder(stringArg1, stringArg2, stringArg3, stringArg4) << endl;;
// Read in four doubles
double doubleArg1, doubleArg2, doubleArg3, doubleArg4;
cin >> doubleArg1;
cin >> doubleArg2;
cin >> doubleArg3;
cin >> doubleArg4;
// Check order of four doubles
cout << "Order: " << CheckOrder(doubleArg1, doubleArg2, doubleArg3, doubleArg4) << endl;;
return 0;
}
Given the definitions of main(), Read() and Write(), complete the following code by implementing the following member functions:
template<typename TheType> vector<TheType> GetStatistics(const vector<TheType>& list)
template<typename TheType> void Run(vector<TheType>& list)
Read()
with the vector parameter as an argument. Read()
stores 5 input values into the vector parameterWrite()
to output the sorted vectorGetStatistics()
with the sorted vector as an argument. GetStatistics()
returns a vector containing the minimum, median, and the maximum values of the sorted vectorWrite()
to output the vector returned by GetStatistics()
Note: vector.size()
returns a long unsigned int, not an int.
Hint: Use the built-in sort function to sort a vector.
1 3 5 9 7
2.2 3.3 1.1 4.4 5.5
one two three four five
1 3 5 7 9
1 5 9
1.1 2.2 3.3 4.4 5.5
1.1 3.3 5.5
five four one three two
five one two
Complete the following code:
Answer:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm> // to use sort()
using namespace std;
const int NUM_VALUES = 5;
// Input NUM_VALUES of TheType into the vector parameter
template<typename TheType> void Read(vector<TheType>& list) {
for (int j = 0; j < NUM_VALUES; ++j) {
cin >> list.at(j);
}
}
// Output the elements of the vector parameter
template<typename TheType> void Write(const vector<TheType>& list) {
long unsigned int j;
for (j = 0; j < list.size(); ++j) {
cout << list.at(j) << " ";
}
}
// Return the min, median, and max of the vector parameter in a new vector
template<typename TheType> vector<TheType> GetStatistics(const vector<TheType>& list) {
vector<TheType> statistics(3);
statistics.at(0) = list.at(0);
statistics.at(1) = list.at(list.size() / 2);
statistics.at(2) = list.at(list.size() - 1);
return statistics;
}
// Read values into a vector, sort the vector, output the sorted vector,
// then output the min, median, and max of the sorted vector
template<typename TheType> void Run(vector<TheType>& list) {
vector<TheType> statistics(3);
Read(list);
sort(list.begin(), list.end());
Write(list);
cout << endl;
statistics = GetStatistics(list);
Write(statistics);
cout << endl;
}
int main() {
vector<int> integers(NUM_VALUES);
Run(integers);
cout << endl;
vector<double> doubles(NUM_VALUES);
Run(doubles);
cout << endl;
vector<string> strings(NUM_VALUES);
Run(strings);
return 0;
}
Multiple classes may be nearly identical, differing only in their data types. The following shows a class managing three int numbers, and a nearly identical class managing three short numbers.
class TripleInt {
public:
TripleInt(int val1 = 0, int val2 = 0, int val3 = 0);
void PrintAll() const; // Print all data member values
int MinItem() const; // Return min data member value
private:
int item1; // Data value 1
int item2; // Data value 2
int item3; // Data value 3
};
TripleInt::TripleInt(int i1, int i2, int i3) {
item1 = i1;
item2 = i2;
item3 = i3;
}
// Print all data member values
void TripleInt::PrintAll() const {
cout << "(" << item1 << "," << item2
<< "," << item3 << ")" << endl;
}
// Return min data member value
int TripleInt::MinItem() const {
int minVal;
minVal = item1; // Holds min item value, init to first item
if (item2 < minVal) {
minVal = item2;
}
if (item3 < minVal) {
minVal = item3;
}
return minVal;
}
class TripleShort {
public:
TripleShort(short val1 = 0, short val2 = 0, short val3 = 0);
void PrintAll() const; // Print all data member values
short MinItem() const; // Return min data member value
private:
short item1; // Data value 1
short item2; // Data value 2
short item3; // Data value 3
};
TripleShort::TripleShort(short i1, short i2, short i3) {
item1 = i1;
item2 = i2;
item3 = i3;
}
// Print all data member values
void TripleShort::PrintAll() const {
cout << "(" << item1 << "," << item2
<< "," << item3 << ")" << endl;
}
// Return min data member value
short TripleShort::MinItem() const {
short minVal;
minVal = item1; // Holds min item value, init to first item
if (item2 < minVal) {
minVal = item2;
}
if (item3 < minVal) {
minVal = item3;
}
return minVal;
}
Writing and maintaining redundant classes that only differ by data type can be time consuming and error prone. C++ supports a better approach.
A class template is a class definition having a special type parameter that may be used in place of types in the class. A variable declared of that class type must indicate a specific type.
#include <iostream>
using namespace std;
template<typename TheType>
class TripleItem {
public:
TripleItem(TheType val1 = 0, TheType val2 = 0, TheType val3 = 0);
void PrintAll() const; // Print all data member values
TheType MinItem() const; // Return min data member value
private:
TheType item1; // Data value 1
TheType item2; // Data value 2
TheType item3; // Data value 3
};
template<typename TheType>
TripleItem<TheType>::TripleItem(TheType i1, TheType i2, TheType i3) {
item1 = i1;
item2 = i2;
item3 = i3;
}
// Print all data member values
template<typename TheType>
void TripleItem<TheType>::PrintAll() const {
cout << "(" << item1 << "," << item2
<< "," << item3 << ")" << endl;
}
// Return min data member value
template<typename TheType>
TheType TripleItem<TheType>::MinItem() const {
TheType minVal = item1; // Holds value of min item, init to first item
if (item2 < minVal) {
minVal = item2;
}
if (item3 < minVal) {
minVal = item3;
}
return minVal;
}
int main() {
TripleItem<int> triInts(9999, 5555, 6666); // TripleItem class with ints
TripleItem<short> triShorts(99, 55, 66); // TripleItem class with shorts
// Try functions from TripleItem
triInts.PrintAll();
cout << "Min: " << triInts.MinItem() << endl << endl;
triShorts.PrintAll();
cout << "Min: " << triShorts.MinItem() << endl << endl;
return 0;
}
The class definition is preceded by template<typename TheType>
where TheType
can be any identifier. That type is known as a template parameter and can be used throughout the class, such as for parameter types, function return types, or local variable types. The identifier is known as a template parameter, and may be various items such as an int, double, char, string, a pointer or reference type, or even another template parameter.
Any of the class's functions or the constructors must also be preceded by the template
declaration, and have the type angle brackets appended to the name as in TripleItem<TheType>::Print()
. An object of this class can be declared by appending after the class's name a specific type in angle brackets, such as TripleItem<short> triShorts(99, 55, 66);
.
GenType
throughout, where GenType
is intended to be chosen by the programmer when declaring a variable of this class. What should be the code that immediately precedes the class definition?Answer: template<typename GenType>
Answer: True. Type-independent code can significantly improve code reuse. The vector class template is a great example -- the same code handles numerous different types, like int, string, and even user-defined types.
template<typename T>
class Vehicle { ... }
, what are the appropriate variable declaration(s) of that class?template<typename T> Vehicle
Vehicle<T> v1
Vehicle<int> v1
Vehicle<short> v1
Answer: Vehicle<int> v1
, and Vehicle<short> v1
. "T" is the generic type used in the class template, acting as a placeholder for the actual type. A variable declaration must now specify the actual type
A template may have multiple parameters, separated by commas.
template<typename T1, typename T2>
class ClassName {
}
Earlier versions of C++ used the word "class" rather than "typename". Though misleading (the type need not be a class, but can be int or double, for example), the word class is still allowed for backwards compatibility, and much existing C++ code uses that word.
Modify the TimeHrMn class to utilize a class template. Note that the main() function passes int and double as parameters for the SetTime() member function.
Answer:
#include <iostream>
using namespace std;
template<typename T>
class TimeHrMn {
public:
void SetTime(T userMin);
void PrintTime() const;
private:
int hrsVal;
T minsVal;
};
template<typename T>
void TimeHrMn<T>::SetTime(T userMin) {
minsVal = userMin;
hrsVal = userMin / 60.0;
}
template<typename T>
void TimeHrMn<T>::PrintTime() const {
cout << "Hours: " << hrsVal << " ";
cout << "Minutes: " << minsVal << endl;
}
int main() {
TimeHrMn<int> usrTimeInt;
TimeHrMn<double> usrTimeDbl;
usrTimeInt.SetTime(135);
usrTimeInt.PrintTime();
usrTimeDbl.SetTime(135.0);
usrTimeDbl.PrintTime();
return 0;
}
Define a class StatePair
with two template types (T1 and T2), constructors, mutators, accessors, and a PrintInfo()
method.
Three vectors have been pre-filled with StatePair
data in main()
:
vector<StatePair <int, string>> zipCodeState
: ZIP code - state abbreviation pairsvector<StatePair<string, string>> abbrevState
: state abbreviation - state name pairsvector<StatePair<string, int>> statePopulation
: state name - population pairsComplete main()
to use an input Zip code to retrieve the correct state abbreviation from the vector zipCodeState
. Then use the state abbreviation to retrieve the state name from the vector abbrevState
. Lastly, use the state name to retrieve the correct state name/population pair from the vector statePopulation
and output the pair.
21044
Maryland: 6079602
Download zip code and population data (abbreviation_state.txt, state_population.txt, zip_code_state.txt) from here by clicking on "Download ZIP"
Answer:
#ifndef STATEPAIR
#define STATEPAIR
using namespace std;
template<typename T1, typename T2>
class StatePair {
public:
StatePair();
StatePair(T1 userKey, T2 userValue);
void SetKey(T1 newKey);
void SetValue(T2 newVal);
T1 GetKey();
T2 GetValue();
void PrintInfo();
private:
T1 key;
T2 value;
};
template<typename T1, typename T2>
StatePair<T1, T2>::StatePair(){}
template<typename T1, typename T2>
StatePair<T1, T2>::StatePair(T1 userKey, T2 userValue) {
key = userKey;
value = userValue;
}
template<typename T1, typename T2>
void StatePair<T1, T2>::SetKey(T1 newKey) {
key = newKey;
}
template<typename T1, typename T2>
void StatePair<T1, T2>::SetValue(T2 newVal) {
value = newVal;
}
template<typename T1, typename T2>
T1 StatePair<T1, T2>::GetKey() {
return key;
}
template<typename T1, typename T2>
T2 StatePair<T1, T2>::GetValue() {
return value;
}
template<typename T1, typename T2>
void StatePair<T1, T2>::PrintInfo() {
cout << key << ": " << value << endl;
}
#endif
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include "StatePair.h"
using namespace std;
int main() {
ifstream inFS;
int zip, population;
string abbrev, state;
unsigned int i;
vector<StatePair <int, string>> zipCodeState;
vector<StatePair<string, string>> abbrevState;
vector<StatePair<string, int>> statePopulation;
inFS.open("zip_code_state.txt");
if (!inFS.is_open()) {
cout << "Could not open file zip_code_state.txt." << endl;
return 1;
}
while (!inFS.eof()) {
StatePair <int, string> temp;
inFS >> zip;
if (!inFS.fail()) temp.SetKey(zip);
inFS >> abbrev;
if (!inFS.fail()) temp.SetValue(abbrev);
zipCodeState.push_back(temp);
}
inFS.close();
inFS.open("abbreviation_state.txt");
if (!inFS.is_open()) {
cout << "Could not open file abbreviation_state.txt." << endl;
return 1;
}
while (!inFS.eof()) {
StatePair <string, string> temp;
inFS >> abbrev;
if (!inFS.fail()) temp.SetKey(abbrev);
getline(inFS, state);
getline(inFS, state);
state = state.substr(0, state.size()-1);
if (!inFS.fail()) temp.SetValue(state);
abbrevState.push_back(temp);
}
inFS.close();
inFS.open("state_population.txt");
if (!inFS.is_open()) {
cout << "Could not open file state_population.txt." << endl;
return 1;
}
while (!inFS.eof()) {
StatePair <string, int> temp;
getline(inFS, state);
state = state.substr(0, state.size()-1);
if (!inFS.fail()) temp.SetKey(state);
inFS >> population;
if (!inFS.fail()) temp.SetValue(population);
getline(inFS, state);
statePopulation.push_back(temp);
}
inFS.close();
cin >> zip;
for (i = 0; i < zipCodeState.size(); i++)
if (zipCodeState.at(i).GetKey() == zip)
abbrev = zipCodeState.at(i).GetValue();
for (i = 0; i < abbrevState.size(); i++)
if (abbrevState.at(i).GetKey() == abbrev)
state = abbrevState.at(i).GetValue();
for (i = 0; i < statePopulation.size(); i++)
if (statePopulation.at(i).GetKey() == state)
statePopulation.at(i).PrintInfo();
return 0;
}
Your exercise answers are saved to this Google doc