14.17 - 重载运算符和函数模板
Key Takeaway
-
In lesson8.14 - 函数模板的实例化,we discussed how the compiler will use function templates to instantiate functions, which are then compiled. We also noted that these functions may not compile, if the code in the function template tries to perform some operation that the actual type doesn’t support (such as adding integer value 1
to a std::string
).
In this lesson, we’ll take a look at a few examples where our instantiated functions won’t compile because our actual class types don’t support those operators, and show how we can define those operators so that the instantiated functions will then compile.
Operators, function calls, and function templates
First, let’s create a simple class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
COPY
and define a max
function template:
1 2 3 4 5 |
|
COPY
Now, let’s see what happens when we try to call max()
with object of type Cents
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
C++ will create a template instance for max() that looks like this:
1 2 3 4 5 |
|
And then it will try to compile this function. See the problem here? C++ has no idea how to evaluate x < y
when x
and y
are of type Cents
! Consequently, this will produce a compile error.
To get around this problem, simply overload operator<
for any class we wish to use max
with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
This works as expected, and prints:
1 |
|
Another example
Let’s do one more example of a function template not working because of missing overloaded operators.
The following function template will calculate the average of a number of objects in an array:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
COPY
This produces the values:
1 2 |
|
As you can see, it works great for built-in types!
Now let’s see what happens when we call this function on our Cents
class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
The compiler goes berserk and produces a ton of error messages! The first error message will be something like this:
1 |
|
Remember that average()
returns a Cents
object, and we are trying to stream that object to std::cout
using operator<<
. However, we haven’t defined the operator<<
for our Cents
class yet. Let’s do that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
If we compile again, we will get another error:
1 |
|
This error is actually being caused by the function template instance created when we call average(const Cents*, int)
. Remember that when we call a templated function, the compiler “stencils” out a copy of the function where the template type parameters (the placeholder types) have been replaced with the actual types in the function call. Here is the function template instance for average()
when T
is a Cents
object:
1 2 3 4 5 6 7 8 9 10 |
|
COPY
The reason we are getting an error message is because of the following line:
1 |
|
COPY
In this case, sum
is a Cents
object, but we have not defined operator+=
for Cents
objects! We will need to define this function in order for average()
to be able to work with Cents
. Looking forward, we can see that average()
also uses the operator/=
, so we will go ahead and define that as well:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
COPY
Finally, our code will compile and run! Here is the result:
1 |
|
Note that we didn’t have to modify average()
at all to make it work with objects of type Cents
. We simply had to define the operators used to implement average()
for the Cents
class, and the compiler took care of the rest!