Back to Item 20: Facilitate the return value optimization
Continue to Item 22: Consider using op= instead of stand-alone op

Item 21: Overload to avoid implicit type conversions.

Here's some code that looks nothing if not eminently reasonable:

    class UPInt {                                 // class for unlimited
    public:                                       // precision integers
      UPInt();
      UPInt(int value);
      ...

    };

    // For an explanation of why the return value is const,
    // see Item E21
    const UPInt operator+(const UPInt& lhs, const UPInt& rhs);

    UPInt upi1, upi2;

    ...

    UPInt upi3 = upi1 + upi2;

There are no surprises here. `upi1` and `upi2` are both `UPInt` objects, so adding them together just calls `operator+` for `UPInts`.

Now consider these statements:

    upi3 = upi1 + 10;

    upi3 = 10 + upi2;

These statements also succeed. They do so through the creation of temporary objects to convert the integer 10 into `UPInts` (see Item 19).

It is convenient to have compilers perform these kinds of conversions, but the temporary objects created to make the conversions work are a cost we may not wish to bear. Just as most people want government benefits without having to pay for them, most C++ programmers want implicit type conversions without incurring any cost for temporaries. But without the computational equivalent of deficit spending, how can we do it?

We can take a step back and recognize that our goal isn't really type conversion, it's being able to make calls to `operator+` with a combination of `UPInt` and `int` arguments. Implicit type conversion happens to be a means to that end, but let us not confuse means and ends. There is another way to make mixed-type calls to `operator+` succeed, and that's to eliminate the need for type conversions in the first place. If we want to be able to add `UPInt` and `int` objects, all we have to do is say so. We do it by declaring several functions, each with a different set of parameter types:

    const UPInt operator+(const UPInt& lhs,      // add UPInt
                          const UPInt& rhs);     // and UPInt

    const UPInt operator+(const UPInt& lhs,      // add UPInt
                          int rhs);              // and int

    const UPInt operator+(int lhs,               // add int and
                          const UPInt& rhs);     // UPInt

    UPInt upi1, upi2;

    ...

    UPInt upi3 = upi1 + upi2;                    // fine, no temporary for
                                                 // upi1 or upi2

    upi3 = upi1 + 10;                            // fine, no temporary for
                                                 // upi1 or 10

    upi3 = 10 + upi2;                            // fine, no temporary for
                                                 // 10 or upi2

Once you start overloading to eliminate type conversions, you run the risk of getting swept up in the passion of the moment and declaring functions like this:

    const UPInt operator+(int lhs, int rhs);           // error!

The thinking here is reasonable enough. For the types `UPInt` and `int`, we want to overload on all possible combinations for `operator+`. Given the three overloadings above, the only one missing is `operator+` taking two `int` arguments, so we want to add it.

Reasonable or not, there are rules to this C++ game, and one of them is that every overloaded operator must take at least one argument of a user-defined type. `int` isn't a user-defined type, so we can't overload an operator taking only arguments of that type. (If this rule didn't exist, programmers would be able to change the meaning of predefined operations, and that would surely lead to chaos. For example, the attempted overloading of `operator+` above would change the meaning of addition on `int`s. Is that really something we want people to be able to do?)

Overloading to avoid temporaries isn't limited to operator functions. For example, in most programs, you'll want to allow a `string` object everywhere a `char*` is acceptable, and vice versa. Similarly, if you're using a numerical class like `complex` (see Item 35), you'll want types like `int` and `double` to be valid anywhere a numerical object is. As a result, any function taking arguments of type `string`, `char*`, `complex`, etc., is a reasonable candidate for overloading to eliminate type conversions.

Still, it's important to keep the 80-20 rule (see Item 16) in mind. There is no point in implementing a slew of overloaded functions unless you have good reason to believe that it will make a noticeable improvement in the overall efficiency of the programs that use them.

Back to Item 20: Facilitate the return value optimization
Continue to Item 22: Consider using op= instead of stand-alone op