Overload resolution is the process that selects the function to call for a given call expression. Consider the following simple example:
void display_num(int); // #1
void display_num(double); // #2
int main()
{
display_num(399); // #1 matches better than #2
display_num(3.99); // #2 matches better than #1
}
In this example, the function name display_num()
is said to be overloaded. When this name is used in a call, a C++ compiler must therefore distinguish between the various candidates using additional information; mostly, this information is the types of the call arguments. In our example, it makes intuitive sense to call the int
version when the function is called with an integer argument and the double
version when a floating-point argument is provided. The formal process that attempts to model this intuitive choice is the overload resolution process.
The general ideas behind the rules that guide overload resolution are simple enough, but the details have become quite complex during the C++ standardization process. This complexity was driven mostly by the desire to support various real-world examples that intuitively (to a human) seem to have an “obviously best match,” but when trying to formalize this intuition, various subtleties arose.
In this appendix, we provide a reasonably detailed survey of the overload resolution rules. However, the complexity of this process is such that we do not claim to cover every part of the topic.
Overload resolution is just one part of the complete processing of a function call. In fact, it is not part of every function call. First, calls through function pointers and calls through pointers to member functions are not subject to overload resolution because the function to call is entirely determined (at run time) by the pointers. Second, function-like macros cannot be overloaded and are therefore not subject to overload resolution.
At a very high level, a call to a named function can be processed in the following way:
• The name is looked up to form an initial overload set.
• If necessary, this set is adjusted in various ways (e.g., template argument deduction and substitution occurs, which can cause some function template candidates to be discarded).
• Any candidate that doesn’t match the call at all (even after considering implicit conversions and default arguments) is eliminated from the overload set. This results in a set of viable function candidates.
• Overload resolution is performed to find a best candidate. If there is one, it is selected; otherwise, the call is ambiguous.
• The selected candidate is checked. For example, if it is a deleted function (i.e., one defined with = delete
) or an inaccessible private member function, a diagnostic is issued.
Each of these steps has its own subtleties, but overload resolution is arguably the most complex. Fortunately, a few simple principles clarify the majority of situations. We examine these principles next.
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):
1. Perfect match. The parameter has the type of the expression, or it has a type that is a reference to the type of the expression (possibly with added const
and/or volatile
qualifiers).
2. Match with minor adjustments. This includes, for example, the decay of an array variable to a pointer to its first element or the addition of const
to match an argument of type int**
to a parameter of type int const* const*
.
3. Match with promotion. Promotion is a kind of implicit conversion that includes the conversion of small integral types (such as bool
, char
, short
, and sometimes enumerations) to int
, unsigned int
, long
, or unsigned long
, and the conversion of float
to double
.
4. Match with standard conversions only. This includes any sort of standard conversion (such as int
to float
) or conversion from a derived class to one of its public, unambiguous base classes but excludes the implicit call to a conversion operator or a converting constructor.
5. Match with user-defined conversions. This allows any kind of implicit conversion.
6. Match with ellipsis (…
). An ellipsis parameter can match almost any type. However, there is one exception: Class types with a nontrivial copy constructor may or may not be valid (implementations are free to allow or disallow this).
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);
// #5
};
int f3(X);
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. For example:
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 assignment to str2
finds no viable function truncate()
; hence overload resolution is not performed at all.
In the context of template argument deduction, recall also that an rvalue reference to a template parameter can deduce to either an lvalue reference type (after reference collapsing) if the corresponding argument is an lvalue or to an rvalue reference type if that argument is an rvalue (see Section 15.6 on page 277). For example:
template<typename T> void strange(T&&, T&&);
template<typename T> void bizarre(T&&, double&&);
int main()
{
strange(1.2, 3.4); // OK: with T deduced to double
double val = 1.2;
strange(val, val); // OK: with T deduced to double&
strange(val, 3.4); // ERROR: conflicting deductions
bizarre(val, val); // ERROR: lvalue val doesn’t match double&&
}
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.
Calls 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 <cstddef>
class BadString {
public:
BadString(char const*);
…
// character access through subscripting:
char& operator[] (std::size_t); // #1
char const& operator[] (std::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
parameter).
By default, a nonstatic member function has an implicit *this
parameter that is an lvalue reference type, but C++11 introduced syntax to make it an rvalue reference type. For example:
struct S {
void f1(); // implicit *this parameter is an lvalue reference (see below)
void f2() &&; // implicit *this parameter is an rvalue reference
void f3() &; // implicit *this parameter is an lvalue reference
};
As you can tell from this example, it is possible not only to make the implicit parameter an rvalue reference (with the &&
suffix) but also to affirm the lvalue reference case (with the &
suffix). Interestingly, specifying the &
suffix is not exactly equivalent to leaving it off: An old special-case permits an rvalue to be bound to an lvalue reference to non-const
type when that reference is the traditional implicit *this
parameter, but that (somewhat dangerous) special case no longer applies if the lvalue reference treatment was requested explicitly. So, with the definition of S
specified above:
int main()
{
S().f1(); // OK: old rule allows rvalue S() to match implied
// lvalue reference type S& of *this
S().f2(); // OK: rvalue S() matches rvalue reference type
// of *this
S().f3(); // ERROR: rvalue S() cannot match explicit lvalue
// reference type of *this
}
For an argument of type X
, there are four common parameter types that constitute a perfect match: X, X&, X const&
, and X&& (X const&&
is also an exact match, but it is rarely used). However, it is rather common to overload a function on two kinds of references. Prior to C++11, this meant cases like these:
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
}
Here, the version without the extra const
is preferred for lvalues, whereas only the version with const
can match rvalues.
With the addition of rvalue references in C++11, another common case of two perfect matches needing to be distinguished is illustrated by the following example:
struct Value {
…
};
// #1
void pass(Value const&);
void pass(Value&&); // #2
void g(X&& x)
{
pass(x); // calls #1 , because x is an lvalue
pass(X()); // calls #2 , because X() is an rvalue (in fact, prvalue)
pass(std::move(x)); // calls #2 , because std::move(x) is an rvalue (in fact, xvalue)
}
This time, the version taking an rvalue reference is considered a better match for rvalues, but it cannot match lvalues.
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
}
The previous section covers most of the overloading situations encountered in everyday C++ programming. There are, unfortunately, many more rules and exceptions to these rules—more than is reasonable to present in a book that is not really about function overloading in C++. Nonetheless, we discuss some of them here in part because they apply somewhat more often than other rules and in part to provide a sense for how deep the details go.
When all other aspects of overload resolution are equal, a nontemplate function is preferred over an instance of a template (it doesn’t matter whether that instance is generated from the generic template definition or whether it is provided as an explicit specialization). For example:
template<typename T> int f(T); // #1
void f(int); // #2
int main()
{
return f(7); // ERROR: selects #2 , which doesn’t return a value
}
This example also clearly illustrates that overload resolution normally does not involve the return type of the selected function.
However, when other aspects of overload resolution slightly differ (such as having different const
and reference qualifiers), first the general rules of overload resolution apply. This effect can easily accidentally cause surprising behavior, when member functions are defined that accept the same arguments as copy or move constructors. See Section 16.2.4 on page 333 for details.
If the choice is between two templates, then the most specialized of the templates is preferred (provided one is actually more specialized than the other). See Section 16.2.2 on page 330 for a thorough explanation of this concept. One special case of this distinction occurs when two templates only differ in that one adds a trailing parameter packs: The template without the pack is considered more specialized and is therefore preferred if it matches the call. Section 4.1.2 on page 57 discusses an example of this situation.
An implicit conversion can, in general, be a sequence of elementary conversions. Consider the following code example:
class Base {
public:
operator short() const;
};
class Derived : public Base {
};
void count(int);
void process(Derived const& object)
{
count(object); // matches with user-defined conversion
}
The call count(object)
works because object
can implicitly be converted to int
. However, this conversion requires several steps:
1. A conversion of object
from Derived const
to Base const
(this is a glvalue conversion; it preserves the identity of the object)
2. A user-defined conversion of the resulting Base const
object to type short
3. A promotion of short
to int
This is the most general kind of conversion sequence: a standard conversion (a derived-to-base conversion, in this case), followed by a user-defined conversion, followed by another standard conversion. Although there can be at most one user-defined conversion in a conversion sequence, it is also possible to have only standard conversions.
An important principle of overload resolution is that a conversion sequence that is a subsequence of another conversion sequence is preferable over the latter sequence. If there were an additional candidate function
void count(short);
in the example, it would be preferred for the call count(object)
because it doesn’t require the third step (promotion) in the conversion sequence.
Pointers and pointers to members undergo various special standard conversions, including
• Conversions to type bool
• Conversions from an arbitrary pointer type to void*
• Derived-to-base conversions for pointers
• Base-to-derived conversions for pointers to members
Although all of these can cause a “match with standard conversions only,” they are not ranked equally.
First, conversions to type bool
(both from a regular pointer and from a pointer to a member) are considered worse than any other kind of standard conversion. For example:
;void check(void*); // #1
void check(bool); // #2
void rearrange (Matrix* m)
{
check(m); // calls #1
…
}
Within the category of regular pointer conversions, a conversion to type void*
is considered worse than a conversion from a derived class pointer to a base class pointer. Furthermore, if conversions to different classes related by inheritance exist, a conversion to the most derived class is preferred. Here is another short example:
class Interface {
…
};
class CommonProcesses : public Interface {
…
};
class Machine : public CommonProcesses {
…
};
char* serialize(Interface*); // #1
char* serialize(CommonProcesses*); // #2
void dump (Machine* machine)
{
char* buffer = serialize(machine); // calls #2
…
}
The conversion from Machine*
to CommonProcesses*
is preferred over the conversion to Interface*
, which is fairly intuitive.
A very similar rule applies to pointers to members: Between two conversions of related pointer-to-member types, the “closest base” in the inheritance graph (i.e., the least derived) is preferred.
Initializer list arguments (initializers passed with in curly braces) can be converted to several different kinds of parameters: initializer_lists, class types with an initializer_list
constructor, class types for which the initializer list elements can be treated as (separate) parameters to a constructor, or aggregate class types whose members can be initialized by the elements of the initializer list. The following program illustrates these cases:
overload/initlist.cpp
#include <initializer_list>
#include <string>
#include <vector>
#include <complex>
#include <iostream>
void f(std::initializer_list<int>) {
std::cout << "#1\n";
}
void f(std::initializer_list<std::string>) {
std::cout << "#2\n";
}
void g(std::vector<int> const& vec) {
std::cout << "#3\n";
}
void h(std::complex<double> const& cmplx) {
std::cout << "#4\n";
}
struct Point {
int x, y;
};
void i(Point const& pt) {
std::cout << "#5\n";
}
int main()
{
f({1, 2, 3}); // prints #1
f({"hello", "initializer", "list"}); // prints #2
g({1, 1, 2, 3, 5}); // prints #3
h({1.5, 2.5}); // prints #4
i({1, 2}); // prints #5
}
In the first two calls to f()
, the initializer list arguments are converted to std::initializer_list
values, which involves converting each of the elements in the initializer list to the element type of the std::initializer_list
. In the first call, all of the elements are already of type int
, so no additional conversion is needed. In the second call, each string literal in the initializer list is converted to a std::string
by calling the string(char const*)
constructor. The third call (to g()
) performs a user-defined conversion using the std::vector(std::initializer_list<int>)
constructor. The next call invokes the std::complex(double, double)
constructor, as if one had written std::complex<double>(1.5, 2.5)
. The final call performs aggregate initialization, which initializes the members of an instance of the Point
class from the elements in the initializer list without calling a constructor of Point
.3
There are several interesting overloading cases for initializer lists. When converting an initializer list to an initializer_list
, as in the first two calls of the example above, the overall conversion is given the same ranking as the worst conversion from any given element in the initializer list to the element type of the initializer_list
(i.e., the T
in initializer_list<T>
). This can lead to some surprises, as in the following example:
overload/initlistovl.cpp
#include <initializer_list>
#include <iostream>
void ovl(std::initializer_list<char>) { //#1
std::cout << "#1\n";
}
void ovl(std::initializer_list<int>) { //#2
std::cout << "#2\n";
}
int main()
{
ovl({’h’, ’e’, ’l’, ’l’, ’o’, ’\0’}); //prints #1
ovl({’h’, ’e’, ’l’, ’l’, ’o’, 0}); //prints #2
}
In the first call to ovl()
, each element of the initializer list is a char
. For the first ovl()
function, these elements require no conversion at all. For the second ovl()
function, these elements require a promotion to int
. Because the perfect match is better than a promotion, the first call to ovl()
calls #1 .
In the second call to ovl()
, the first five elements are of type char
, while the last is of type int
. For the first ovl()
function, the char
elements are a perfect match, but the int
requires a standard conversion, so the overall conversion is ranked as a standard conversion. For the second ovl()
function, the char
elements require a promotion to int
, while the int
element at the end is a perfect match. The overall conversion for the second ovl()
function is ranked as a promotion, which makes it a better candidate than the first ovl()
, even though only a single element’s conversion was better.
When initializing an object of class type with an initializer list, as in the calls to g()
and h()
in our original example, overload resolution proceeds in two phases:
1. The first phase considers only initializer-list constructors, that is, constructors whose only nonde-faulted parameter is of type std::initializer_list<T>
for some type T
(after removing the top-level reference and const
/volatile
qualifiers).
2. If no such viable constructor is found, then the second phase considers all other constructors. There is one exception to this rule: If the initializer list is empty and the class has a default constructor, the first phase is skipped so that the default constructor will be called.
The effect of this rule is that any initializer-list constructor is a better match than any non-initializer-list constructor, as illustrated in the following example:
overload/initlistctor.cpp
#include <initializer_list>
#include <string>
#include <iostream>
template<typename T>
struct Array {
Array(std::initializer_list<T>) {
std::cout << "#1\n";
}
Array(unsigned n, T const&) {
";
std::cout << "#2\n
}
};
void arr1(Array<int>) {
}
void arr2(Array<std::string>) {
}
int main()
{
arr1({1, 2, 3, 4, 5}); // prints #1
arr1({1, 2}); // prints #1
arr1({10u, 5});
// prints #1
, "initializer", "list"}); //prints
arr2({"hello"#1
}); //prints
arr2({10, "hello"#2
}
Note that the second constructor, which takes an unsigned
and a T const&
, won’t be called when initializing an Array<int>
object from an initializer list, because its initializer-list constructor is always a better match than its non-initializer-list constructors. With Array<string>
, however, the non-initializer-list constructor will be called when the initializer-list constructor is not viable, as in the second call to arr2()
.
We mentioned earlier that after the name of a function has been looked up to create an initial overload set, the set is tweaked in various ways. An interesting situation arises when a call expression refers to a class type object instead of a function. In this case, there are two potential additions to the overload set.
The first addition is straightforward: Any member operator ()
(the function call operator) is added to the set. Objects with such operators are usually called functors or function objects (see Section 11.1 on page 157).
A less obvious addition occurs when a class type object contains an implicit conversion operator to a pointer to a function type (or to a reference to a function type).4 In such situations, a dummy (or surrogate) function is added to the overload set. This surrogate function candidate is considered to have an implied parameter of the type designated by the conversion function, in addition to parameters with types corresponding to the parameter types in the destination type of that conversion function. An example makes this much clearer:
using FuncType = void (double, int);
class IndirectFunctor {
public:
…
void operator()(double, double) const;
operator FuncType*() const;
};
void activate(IndirectFunctor const& funcObj)
{
funcObj(3, 5); // ERROR: ambiguous
}
The call funcObj(3, 5)
is treated as a call with three arguments: funcObj, 3
, and 5. The viable function candidates include the member operator()
(which is treated as having parameter types IndirectFunctor const&, double
, and double
) and a surrogate function with parameters of type FuncType*, double
, and int
. The surrogate function has a worse match for the implied parameter (because it requires a user-defined conversion), but it has a better match for the last parameter; hence the two candidates cannot be ordered. The call is therefore ambiguous.
Surrogate functions are in the most obscure corners of C++ and rarely occur in practice (fortunately).
So far we have discussed overloading in the context of determining which function should be called in a call expression. However, there are a few other contexts in which a similar selection must be made.
The first context occurs when the address of a function is needed. Consider the following example:
int numElems(Matrix const&); // #1
int numElems(Vector const&); // #2
…
int (*funcPtr)(Vector const&) = numElems; // selects #2
Here, the name numElems
refers to an overload set, but only the address of one function in that set is desirable. Overload resolution then attempts to match the required function type (the type of funcPtr
in this example) to the available candidates.
The other context that requires overload resolution is initialization. Unfortunately, this is a topic fraught with subtleties that are beyond what can be covered in an appendix. However, a simple example at least illustrates this additional aspect of overload resolution:
#include <string>
class BigNum {
public:
BigNum(long n);
// #1
BigNum(double n);
// #2
BigNum(std::string const&);
// #3
…
operator double(); // #4
operator long(); // #5
…
};
void initDemo()
{
BigNum bn1(100103);
// selects #1
BigNum bn2("7057103224.095764
"); //selects #3
int in = bn1; // selects #5
}
In this example, overload resolution is needed to select the appropriate constructor or conversion operator. Specifically, the initialization of bn1
calls the first constructor, that of bn2
calls the third constructor, and that of in()
calls operator long()
. In the vast majority of cases, the overloading rules produce the intuitive result. However, the details of these rules are quite complex, and some applications rely on some of the more obscure corners in this area of the C++ language.
1 It could also be of type MyClass volatile&
or MyClass const volatile&
if the member function was volatile
, but this is extremely rare.
2 Note that the ambiguity exists only on platforms for which size_t
is a synonym for unsigned int
. On platforms for which it is a synonym for unsigned long
, the type ptrdiff_t
is a type alias of long
, and no ambiguity exists because the built-in subscript operator also requires a conversion of the subscript expression.
3 Aggregate initialization is only available for aggregate types in C++, which are either arrays or simple, C-like classes that have no user-provided constructors, no private or protected nonstatic data members, no base classes, and no virtual functions. Prior to C++14, they must also not have a default member initializer. Since C++17, public base classes are allowed.
4 The conversion operator must also be applicable in the sense that, for example, a non-const
operator is not considered for const
objects.