When the compiler tries to match actual arguments against the arguments in function declarations, it can supply standard or user-defined conversions to obtain the correct type if no exact match can be found. The application of conversions is subject to these rules:
The resultant sequence of conversions, if any, is called the best matching sequence. There are several ways to convert an object of type int to type unsigned long using standard conversions (described in Chapter 3, Standard Conversions):
The first sequence, although it achieves the desired goal, is not the best matching sequence — a shorter sequence exists.
Table 12.1 shows a group of conversions, called trivial conversions, that have a limited effect on determining of which sequence is the best matching. The instances in which trivial conversions affect choice of sequence are discussed in the list following the table.
Table 12.1 Trivial Conversions
Convert from Type | Convert to Type |
type-name | type-name& |
type-name& | type-name |
type-name[ ] | type-name* |
type-name( argument-list ) | (*type-name) ( argument-list ) |
type-name | const type-name |
type-name | volatile type-name |
type-name* | const type-name* |
type-name* | volatile type-name* |
The sequence in which conversions are attempted is as follows:
Figure 12.1 Graph Illustrating Preferred Conversions
Conversion from type D*
to type C*
is preferable to conversion from type D*
to type B*
. Similarly, conversion from type D*
to type B*
is preferable to conversion from type D*
to type A*
.
This same rule applies to reference conversions. Conversion from type D&
to type C&
is preferable to conversion from type D&
to type B&
, and so on.
This same rule applies to pointer-to-member conversions. Conversion from type T D::*
to type T C::*
is preferable to conversion from type T D::*
to type T B::*
, and so on (where T
is the type of the member).
The preceding rule applies only along a given path of derivation. Consider the graph shown in Figure 12.2.
Figure 12.2 Multiple-Inheritance Graph Illustrating Preferred Conversions
Conversion from type C*
to type B*
is preferable to conversion from type C*
to type A*
. The reason is that they are on the same path, and B*
is closer. However, conversion from type C*
to type D*
is not preferable to conversion to type A*
; there is no preference because the conversions follow different paths.
User-defined conversions are applied if no built-in promotion or conversion exists. These conversions are selected on the basis of the type of the argument being matched. Consider the following code:
class UDC
{
public:
operator int();
operator long();
};
void Print( int i );
...
UDC udc;
Print( udc );
The available user-defined conversions for class UDC
are from type int and type long. Therefore, the compiler considers conversions for the type of the object being matched: UDC
. A conversion to int exists, and it is selected.
During the process of matching arguments, standard conversions can be applied to both the argument and the result of a user-defined conversion. Therefore, the following code works:
void LogToFile( long l );
...
UDC udc;
LogToFile( udc );
In the preceding example, the user-defined conversion, operator long, is invoked to convert udc
to type long. If no user-defined conversion to type long had been defined, the conversion would have proceeded as follows: Type UDC
would have been converted to type int using the user-defined conversion. Then the standard conversion from type int to type long would have been applied to match the argument in the declaration.
If any user-defined conversions are required to match an argument, the standard conversions are not used when evaluating the best match. This is true even if more than one candidate function requires a user-defined conversion; in such a case, the functions are considered equal. For example:
class UDC1
{
public:
UDC1( int ); // User-defined conversion from int.
};
class UDC2
{
public:
UDC2( long ); // User-defined conversion from long.
};
...
void Func( UDC1 );
void Func( UDC2 );
...
Func( 1 );
Both versions of Func
require a user-defined conversion to convert type int to the class type argument. The possible conversions are:
UDC1
(a user-defined conversion).UDC2
(a two-step conversion).Even though the second of these requires a standard conversion, as well as the user-defined conversion, the two conversions are still considered equal.
Note User-defined conversions are considered conversion by construction or conversion by initialization (conversion function). Both methods are considered equal when considering the best match.