Array dimensions are not passed as part of a function parameter’s type unless that parameter is passed by pointer or reference. The function template init2 declares a to be a reference to a two-dimensional array, so its dimensions R and C are deduced by the template facility, making init2 a handy way to initialize a two-dimensional array of any size. The template init1 does not pass the array by reference, so the sizes must be explicitly specified, although the type parameter can still deduced.
Function template overloading
As with functions, you can overload function templates that have the same name. When the compiler processes a function call in a program, it has to decide which template or ordinary function is the "best" fit for the call. Assuming the existence of the min function template introduced earlier, let’s add some ordinary functions to the mix:.
//: C05:MinTest.cpp
#include
#include
using std::strcmp;
using std::cout;
using std::endl;
template
return (a < b) ? a : b;
}
const char* min(const char* a, const char* b) {
return (strcmp(a, b) < 0) ? a : b;
}
double min(double x, double y) {
return (x < y) ? x : y;
}
int main() {
const char *s2 = "say \"Ni-!\"", *s1 = "knights who";
cout << min(1, 2) << endl; // 1: 1 (template)
cout << min(1.0, 2.0) << endl; // 2: 1 (double)
cout << min(1, 2.0) << endl; // 3: 1 (double)
cout << min(s1, s2) << endl; // 4: knights who (const
// char*)
cout << min<>(s1, s2) << endl; // 5: say "Ni-!"
// (template)
} ///:~
In addition to the function template, this program defines two non-template functions: a C-style string version of min and a double version. If the template doesn’t exist at all, the call in line 1 above have invokes the double version of min because of the standard conversion from int to double. Since the template can generate an int version, however, that is considered a better match (of course!); so that’s what happens. The call in line 2 is an exact match for the double version, of course, and the call in line 3 also invokes the same function, implicitly converting 1 to 1.0. In line 4 the const char* version of min is called directly. In line 5 we force the compiler to use the template facility by appending empty angle brackets to the function name, whereupon it generates a const char* version from the template and uses it (which is verified by the wrong answer—it’s just comparing addresses![52]). If you’re wondering why we used using declarations in lieu of the using namespace std; directive, some compilers include headers behind the scenes that bring in std::min, which would conflict with our declarations of the name min.
As stated above, you can overload templates of the same name, as long as they can be distinguished by the compiler. You could, for example, declare a min function template that processes three arguments:
template
const T& min(const T& a, const T& b, const T& c);
Versions of this template will be generated only for calls to min( ) that have three arguments of the same type.
Taking the address of a generated function template
In a number of situations you need to take the address of a function. For example, you may have a function that takes an argument of a pointer to another function. Of course, it’s possible that this other function might be generated from a template function, so you need some way to take that kind of address:[53]
//: C05:TemplateFunctionAddress.cpp
// Taking the address of a function generated
// from a template.
template
void h(void (*pf)(int*)) {}
template
void g(void (*pf)(T*)) {}
int main() {
// Full type specification:
h(&f
// Type deduction:
h(&f);
// Full type specification:
g
// Type deduction:
g(&f
// Partial (but sufficient) specification
g
} ///:~
This example demonstrates a number of issues. First, even though you’re using templates, the signatures must match. The function h( ) takes a pointer to a function that takes an int* and returns void, and that’s what the template f produces. Second, the function that wants the function pointer as an argument can itself be a template, as in the case of the template g.
In main( ) you can see that type deduction works here too. The first call to h( ) explicitly gives the template argument for f, but since h( ) says that it will only take the address of a function that takes an int*, that part can be deduced by the compiler. With g( ) the situation is even more interesting because two templates are involved. The compiler cannot deduce the type with nothing to go on, but if either f or g is given int, the rest can be deduced.