Skip to content
Lesson 15 of 15

Step 1 of 7 · Reading · ~3 min

Learn

Classes, Inheritance, and Templates

Templates Introduction

A template is a recipe the compiler turns into real code once you name a type. By the end of this lesson you can write a function template, write a class template whose members have type T, and avoid the default-value trap that makes generic code print 0 where it should not.

Function templates

template <typename T> introduces a type parameter named T. Inside the definition, T stands for whatever type the caller uses.

template <typename T>
T twice(T x) {
    return x + x;
}

std::cout << twice(21) << "\n";                   // T = int          -> 42
std::cout << twice(1.25) << "\n";                 // T = double       -> 2.5
std::cout << twice(std::string("ab")) << "\n";    // T = std::string  -> abab

The compiler reads each call, deduces T from the argument, and generates (instantiates) a separate function for each type: one twice<int>, one twice<double>, one twice<std::string>. template <class T> means exactly the same thing; typename is the usual spelling.

A template only works for types that support what its body does. twice needs +, so calling it with the Point class from the classes lesson is a compile error at that call, and the message points into the template body.

Class templates

The same idea applies to a whole class. Every member can use T, and the user picks T in angle brackets:

template <typename T>
class Tally {
    T sum_;
    int times_;
public:
    Tally() : sum_{}, times_{0} {}
    void put(const T& x) { sum_ = sum_ + x; ++times_; }
    T sum() const { return sum_; }
    int times() const { return times_; }
};

Tally<int> scores;
scores.put(4); scores.put(9);
std::cout << scores.sum() << " " << scores.times() << "\n";   // 13 2

Tally<std::string> letters;
letters.put("x"); letters.put("yz");
std::cout << letters.sum() << "\n";                            // xyz

For a class template you write the type yourself: Tally<int>, not Tally. Tally<int> and Tally<std::string> are two unrelated classes stamped from one recipe; you cannot assign one to the other. Taking const T& avoids copying a big T such as a long string, the same reason you used const references in earlier lessons.

The T{} trap

sum_{} is value-initialization: it gives T's "empty" value.

TT{}
int0
double0.0
std::string""

That is the right start for a sum. It is the wrong start for anything that compares against real data:

template <typename T>
T biggest(const std::vector<T>& v) {
    T best{};                       // WRONG start
    for (const T& x : v)
        if (x > best) best = x;
    return best;
}

biggest(std::vector<int>{-5, -2});   // returns 0, but -2 was expected

0 was never in the data, yet it wins because every real value is smaller. The fix is to take the starting value from the data itself: begin with the first element, or keep a flag or counter that says "nothing stored yet" and let the first value in unconditionally.

< on std::string compares character codes left to right, so "Zebra" < "apple" (capital letters come first) and "10" < "9".

Common mistakes

  • Starting smallest/largest at T{}. With values 5 8 6 the minimum comes out 0; with -4 -9 -1 the maximum comes out 0; for words the minimum comes out as an empty string.
  • Writing int where you meant T. A member declared int best; compiles for MinMax<int> and fails to compile for MinMax<std::string>.
  • Expecting dictionary order for words. Zebra, apple, Mango give min Mango, max apple; do not lowercase anything, just use < and >.
  • Forgetting to count. If the counter never moves, the report always says empty.

Your exercise

Finish the class template MinMax<T>: add its private members and fill in add, count, low and high. The starter already reads the input, builds a MinMax<int> and a MinMax<std::string>, and prints them with a given report function. The most likely bug is seeding the smallest and largest values with T{}.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…