Ru-Brd |
Overload resolution ranks the viable candidate functions by comparing how each argument of the call matches the corresponding parameter of the candidates. For one candidate to be considered better than another, the better candidate cannot have any of its parameters be a worse match than the corresponding parameter in the other candidate. The following example illustrates this: void combine(int, double); void combine(long, int); int main() { combine (1, 2); // ambiguous! } In this example, the call to combine() is ambiguous because the first candidate matches the first argument (the literal 1 of type int ) best , whereas the second candidate matches the second argument best . We could argue that int is in some sense closer to long than to double (which supports choosing the second candidate), but C++ does not attempt to define a measure of closeness that involves multiple call arguments. Given this first principle, we are left with specifying how well a given argument matches the corresponding parameter of a viable candidate. As a first approximation we can rank the possible matches as follows (from best to worst):
The following contrived example illustrates some of these matches: int f1(int); // (1) int f1(double); // (2) f1(4); // calls (1): perfect match // ((2) requires a standard conversion) int f2(int); // (3) int f2(char); // (4) f2(true); // calls (3): match with promotion // ((4) requires stronger standard conversion) class X { public: X(int); }; int f3(X); // (5) int f3(...); // (6) f3(7); // calls (5): match with user-defined conversion // ((6) requires a match with ellipsis) Note that overload resolution occurs after template argument deduction, and this deduction does not consider all these sorts of conversions. The following example illustrates this: template <typename T> class MyString { public: MyString(T const*); // converting constructor ... }; template<typename T> MyString<T> truncate(MyString<T> const&, int); int main() { MyString<char> str1, str2; str1 = truncate<char>("Hello World", 5); // OK str2 = truncate("Hello World", 5); // ERROR } The implicit conversion provided through the converting constructor is not considered during template argument deduction. The initialization of str2 finds no viable function truncate() ; hence overload resolution is not performed at all. The previous principles are only a first approximation, but they cover many cases. Yet there are quite a few common situations that are not adequately explained by these rules. We proceed with a brief discussion of the most important refinements of these rules. B.2.1 The Implied Argument for Member FunctionsCalls to nonstatic member functions have a hidden parameter that is accessible in the definition of the member function as *this . For a member function of a class MyClass , the hidden parameter is usually of type MyClass& (for non- const member functions) or MyClass const& (for const member functions). [1] This is somewhat surprising given that this has a pointer type. It would have been nicer to make this equivalent to what is now *this . However, this was part of an early version of C++ before reference types were part of the language, and by the time reference types were added, too much code already depended on this being a pointer.
The hidden *this parameter participates in overload resolution just like the explicit parameters. Most of the time this is quite natural, but occasionally it comes unexpectedly. The following example shows a string-like class that does not work as intended (yet we have seen such code in the real world): #include <stddef.h> class BadString { public: BadString(char const*); ... // character access through subscripting: char& operator[] (size_t); // (1) char const& operator[] (size_t) const; // implicit conversion to null-terminated byte string: operator char* (); // (2) operator char const* (); ... }; int main() { BadString str("correkt"); str[5] = 'c'; // possibly an overload resolution ambiguity! } At first, nothing seems ambiguous about the expression str[5] . The subscript operator at (1) seems like a perfect match. However, it is not quite perfect because the argument 5 has type int , and the operator expects an unsigned integer type ( size_t and std::size_t usually have type unsigned int or unsigned long , but never type int ). Still, a simple standard integer conversion makes (1) easily viable. However, there is another viable candidate: the built-in subscript operator. Indeed, if we apply the implicit conversion operator to str (which is the implicit member function argument), we obtain a pointer type, and now the built-in subscript operator applies. This built-in operator takes an argument of type ptrdiff_t , which on many platforms is equivalent to int and therefore is a perfect match for the argument 5 . So even though the built-in subscript operator is a poor match (by user-defined conversion) for the implied argument, it is a better match than the operator defined at (1) for the actual subscript! Hence the potential ambiguity. [2] To solve this kind of problem portably, you can declare operator [] with a ptrdiff_t parameter, or you can replace the implicit type conversion to char* by an explicit conversion (which is usually recommended anyway).
It is possible for a set of viable candidates to contain both static and nonstatic members . When comparing a static member with a nonstatic member, the quality of the match of the implicit argument is ignored (only the nonstatic member has an implicit *this argument). B.2.2 Refining the Perfect MatchFor an argument of type int , there are three common parameter types that constitute a perfect match: int , int& , and int const& . However, it is rather common to overload a function on both kinds of references: void report(int&); // (1) void report(int const&); // (2) int main() { for (int k = 0; k<10; ++k) { report(k); // calls (1) } report(42); // calls (2) } In such cases the version without the extra const is preferred for lvalues, whereas the version with const is preferred for rvalues. Note that this also applies to the implicit argument of a member function call: class Wonder { public: void tick(); // (1) void tick() const; // (2) void tack() const; // (3) }; void run(Wonder& device) { device.tick(); // calls (1) device.tack(); // calls (3) because there is no non- const version // of Wonder::tack() } Finally, the following modification of our earlier example illustrates that two perfect matches can also create an ambiguity if you overload with and without references: void report(int); // (1) void report(int&); // (2) void report(int const&); // (3) int main() { for (int k = 0; k<10; ++k) { report(k); // ambiguous: (1) and (2) match equally well } report(42); // ambiguous: (1) and (3) match equally well } To summarize:
|
Ru-Brd |