When we define a member function for a templated class, we need to include the template parameters when we write the member functions definitions. For example, if we rewrite our templated Pair<T> to be a class instead of a struct, and we want to define a member function getFirst that returns the first element of the pair, we would do it like this:
template<typename T>
class Pair {
...
T getFirst() const;
...
};
template<typename T>
T Pair<T>::getFirst() const {
return first;
}
The definition of getFirst must be preceded by the template parameter list (line 8). And the full formal name of the function must include the class name and the template parameter, so it is is Pair<T>::getFirst. Given a mystery type T, this is the getFirst function for a Pair of type T.
// Constructor definition for making a Pair<T> from two T values
template<typename T>
Pair<T>::Pair<T>(T a, T b) {...}
// Definition of equality operator for Pair<T>
template<typename T>
bool Pair<T>::operator==(const Pair<T>& other) const {...}
However, once we have established that we are writing code for a Pair<T>, the compiler will assume that any use of just Pair really means Pair<T>. Which means we could simplify our code by omitting the template parameter in certain contexts:
template<typename T>
Pair<T>::Pair(T a, T b) {...} // Note: no <T> after constructor name before parameter list
// Definition of equality operator for Pair<T>
template<typename T>
bool Pair<T>::operator==(const Pair& other) const {...} // Note: no <T> in parameter type
We still need to start the name of each member function with Pair<T>. That is what tells the compiler that this definition is for a Pair of type T. But once that context is set, we do not need to repeat the template parameter for other uses of Pair.
#ifndef PAIR_H
#define PAIR_H
template<typename T>
class Pair {
private:
T first;
T second;
public:
// Constructors are still just called "Pair"
Pair();
Pair(T a, T b);
// Parameter is another Pair of the same type
bool operator==(const Pair<T>& other) const;
T getFirst() const;
T getSecond() const;
};
// Each member function must be defined as a template
// and the class name must be qualified with <T>
template<typename T>
Pair<T>::Pair() {
first = T{}; // Default value for type T
second = T{}; // Default value for type T
}
template<typename T>
Pair<T>::Pair(T a, T b) {
first = a;
second = b;
}
template<typename T>
bool Pair<T>::operator==(const Pair<T>& other) const {
return (first == other.first) && (second == other.second);
}
template<typename T>
T Pair<T>::getFirst() const {
return first;
}
template<typename T>
T Pair<T>::getSecond() const {
return second;
}
#endif
Given that, we can now construct Pairs of any type. We can even make Pairs of Pairs! A pair of pairs of integers would look like Pair<Pair<int>> and it would be constructed with two Pair<int> objects.
Imagine the Pair class had a function copy that took in another Pair of the same type and had a return type of void. (The function would copy the data from the other object into the current one. The other object would not be modified.) What would its prototype look like?