A template can take parameters:
• Type parameters
of “type type”.
• Value parameters
of built-in types such as ints and pointers to functions.
• Template parameters
of “type template”.
Types as Arguments
A type argument is unconstrained. You can implement general constraints as concepts.
Values as Arguments
Example:1
2
3
4
5
6
7
8
9
10template <typename T, int max>
class Buffer {
T v[max];
public:
Buffer();
// ...
};
Buffer<char, 128> cbuf;
Buffer<int, 5000> ibuf;
The argument for a template value
can only be:
• An integral constant expression.
• A pointer or a reference to an object or function with external linkage.
• A nonoverload pointer to a member.
• A null pointer.
The restriction exists to simplify implementation of separately compiled translation units. For double
s and other arguments, we can always find out a better and more clever method to implement.
A type template
parameter can be used as a type later in a template parameter list and it becomes useful when combined with a default template arguments:1
2
3
4
5
6
7template <typename T, T default_value = T{}>
class Vec {
// ...
};
Vec<int, 453> c1;
Vec<int> c11; // default_value is int{}, that is 0.
Operations as Arguments
For the standard-library map
, for a simplified version:1
2
3
4template <typename Key, class V>
class map {
// ...
};
How do we supply comparison criteria for key
s?
Because we can’t hardwrite the criterion, so the notion of soring criterion for a map
could be represented as:
• A template value
argument (e.g., a pointer to a comparison function).
• A template type
argument to the map template determining the type of a comparison object.
A template value argument
It looks like this:1
2
3
4
5template<typename Key, typename V, bool(*cmp)(const Key&, const Key&)>
class map {
public:
map() = default;
}
And at this time, we need user to provide us with a comparative function:1
2
3
4bool insensitive(const string& x, const string& y) {
// compare
}
map<string, int, insensitive> m;
However, it’s not flexible:
• The designer of map will have to decide whether to compare the Key
type using a pointer to function or a function object of some specific type.
• Because the argument types of the comparison operator must depend on the Key
type, it can be hard to provide a default comparison criterion.
A template type argument
This method is used in the standard library:1
2
3
4
5
6
7
8template<typename Key, typename V, typename Compare = std::less<Key>>
class map {
public:
map() = default;
map(Compare c) : cmp(c) {}
//...
Compare cmp{}; //default comparison
};
So we can call map
like below:1
2map<string, int> m1; // use default comparison
map<string, int, std::greater<string>> m2;
And function objects can carry states:1
2Complex_compare f3{"French", 3}; // make a comparison object
map<string, int, Complex_compare> m2{f3}; //compare using f3;
Also, we can use lambda
:
example 1:1
2using Cmp = bool(*)(const string&, const string&);
map<string, int, Cmp> m3{ [](const string& a, const string& b) {return a > b;} };
example 2:1
2auto cmp = [](const string& x, const string& y) const { return x < y; }
map<string, int, decltype(cmp)> m4{cmp};
Templates as Arguments
At some times, we want to use one template as another template’s argument:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17template<typename T, template<typename> class C>
class Xref {
C<T> mems;
C<T*> res;
};
template<typename T>
using My_vec = vector<T>;
Xref<int, My_vec> ref1;
template<typename T>
class My_container {
//...
};
Xref<Record, My_container> ref2;
Only class templates can be template arguments.
Another common case in which a template needs only a container or two is often better handled by passing the container types:1
2
3
4
5
6
7template<typename C1, typename C2>
class Xref2 {
C1 mems;
C2 refs;
};
Xref2<vector<Entry>, vector<int>> x;
Default Template Arguments
Like default function arguments, the default template arguments can be specified and supplied for trailing arguments only:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16void f1(int x = 0, int y); // error: default argument not trailing
void f2(int x = 0, int y = 1); // ok
f2(, 2); //syntax error
f2(2); // call f(2, 1);
template<typename T1 = int, typename T2>
class X1 { // error: default argument not trailing.
};
template<typename T1 = int, typename T2 = double>
class X2 { // ok
};
X2<, float> v1; //syntax error
X2<float> v2; // v2 is an X2<float, double>
Default Function Template Arguments
Naturally, default template arguments can also be useful for function templates.