Overloading[Overload]

11 Overloading[Overload]

When a single name is declared with two or more different declarations in the same scope, the name is overloaded. A declaration that declares an overloaded name is called an overloaded declaration. The set of overloaded declarations that declare the same overloaded name are that name’s overload set.

Only function and function template declarations can be overloaded; variable and type declarations cannot be overloaded.

11.1 Overloadable Declarations[Overload.Decl]

This section specifies the cases in which a function declaration cannot be overloaded. Any program that contains an invalid overload set is ill-formed.

An overload set is invalid if:

  • One or more declaration in the overload set only differ by return type.

    int Yeet(); uint Yeet(); // ill-formed: decls differ only by return type

  • An overload set contains more than one member function declarations with the same parameter-type-list, and one of those declarations is a static member function declaration ([Classes.Static]).

    class Doggo

    static void pet(); void pet(); // ill-formed: cannot be overloaded with ‘static void pet()‘

    void wagTail(); void wagTail() const; // valid

    void bark(int); static void bark(int); // ill-formed: cannot be overloaded with ‘void bark(int)‘

    ;

  • An overload set contains more than one entry function declaration ([Decl.Attr.Entry]).

    void VS(); void VS(int); // valid: only one entry point.

    [shader("vertex")] void Entry();

    [shader("compute")] void Entry(int); // ill-formed: an overload set cannot have more than one entry function

  • An overload set contains more than one function declaration which only differ in const parameter specifiers.

    void G(int); void G(const int); // ill-formed: redeclaration of G(int) void G(int) void G(const int) // ill-formed: redefinition of G(int)

  • An overload set contains more than one function declaration which only differ in parameters mismatching ‘out‘ and ‘inout‘.

    void H(int); void H(in int); // valid: redeclaration of H(int) void H(inout int); // valid: overloading between in and inout is allowed

    void I(in int); void I(out int); // valid: overloading between in and out is allowed

    void J(out int); void J(inout int); // ill-formed: Cannot overload based on out/inout mismatch

11.2 Declaration Matching[Overload.Match]

Two function declarations with the same name and same parameter lists refer to the same function if they are in the same scope (6.4). A function declaration in a containing scope is not the same as a function of the same name and parameter list in a contained scope.

11.3 Overload Resolution[Overload.Res]

Overload resolution is process by which a function call is mapped to the best overloaded function declaration. Overload resolution uses a set of functions called the candidate set, and a list of expressions that comprise the argument list for the call.

Overload resolution selects the function to call in the following contexts:

  • invocation of a function named in a function call expression;

  • invocation of a function call operator on a class object named in function call syntax;

  • invocation of the operator referenced in an expression;

  • invocation of a user-defined conversion function for copy-initialization of an object of class type; and

  • invocation of a user-defined conversion function for initializing an object of non-class type from an expression of class type.

In each of these contexts a unique method is used to construct the overload candidate set and argument expression list.

11.3.1 Candidate Functions and Argument Lists[Overload.Res.Sets]

At each point where an overload must be resolved an implementation will generate a candidate set, containing all possible candidate functions, and the argument list for the overloaded call. The subclauses under this clause define the process by which the candidate set and argument lists are constructed in each context where overload resolution occurs.

A candidate set may include both member and non-member functions to be resolved against the same argument set. Member functions have an extra implicit object parameter, representing the object the function is called on. For the purposes of overload resolution a static member function is considered to have an implicit object parameter.

When appropriate the context shall construct an implied object argument referring to the object operated on.

Any implicit object parameter or implied object argument is always the first parameter or argument.

The type of the implicit object parameter is: lvalue reference cv T; where T is the class containing the declaration of the function, and cv is the cv-qualification on the function declaration.

Implied object arguments behave the same as any explicit argument except that no temporary object shall be created to hold the argument for the implicit object parameter except when the implicit object parameter is a member of a cbuffer-declaration.

If a candidate is a function template, candidate specializations are generated through template argument deduction ([Template.Deduction]), candidates are then handled as any other candidate. A name may refer to more than one function template, in which case candidate functions shall be generated for each function template to form the full candidate set.

11.3.1.1 Function Call Syntax[Overload.Res.Call]

postfix-expression ( expression-listopt )

In a function call (8.6), if the postfix-expression names a candidate set comprised of overloaded functions and/or function templates, the overload resolves as to a named function (11.3.1.2). If the postfix-expression names an object of class type, the overload is resolved as a call to an object of class type (11.3.1.3).

11.3.1.2 Call to a Named Function[Overload.Res.Call.Named]

In a call to a named function, the postfix-expression must be one of the forms:

postfix-expression:
postfix-expression . id-expression
primary-expression

In the first grammar production, the id-expression is the name of the function to be called, and the postfix-expression preceding the . operator. This formation represents a qualified function call, where the postfix-expression must be an object of class type, and the call is looked up as a member function of that object. The function names found by that lookup constitute the overload candidate set for the call. The argument list for the call is the expression-list in the call with the left operand of the . operator prepended as the implicit object parameter (11.3.1).

In the second grammar production, the name is not qualified by an object parameter, so it is an unqualified call. Name lookup occurs as normal for name lookup of a function call (6.5). Function declarations found constitute the candidate set. The candidate set for an unqualified call will be comprised either entirely of non-member functions or entirely of member functions of some class T. If the candidate set is entirely non-member functions, the argument list is the expression-list. If the candidate set is entirely member functions of class T, the argument list is the expression-list with an implied object argument prepended. If the call expression occurs in a context where an implicit object this is in scope and of class type T or a type T′, the this object will be the implicit object argument, otherwise a contrived argument of type T will become the implied object argument. If overload resolution selects a non-static member function, and the implicit object argument is a contrived argument, the call is ill-formed.

11.3.1.3 Call to a Object of Class Type[Overload.Res.Call.Object]

If the primary-expression in the function call expression is a class object of type T, then the set of candidate functions will include the call operators of T obtained by name lookup of the name operator() (6.5).

For this formulation, the argument list consists of the expression-list from the call syntax with the implicit object argument prefixed. The implicit object argument in this form is the object produced from the evaluated postfix-expression.

11.3.1.4 Operators in Expressions[Overload.Res.Oper]

Operators in an expression where no operands have a class or enumeration type are assumed to be built-in operators and interpreted following 8.

If either operand is of class or enumeration type, overload resolution determines which operator function or built-in operator is resolved for the expression.

The table below maps unary and binary operator expressions to equivalent member and non-member function call expressions. In the table @ represents any spellable operator, and a and b represent arguments to the operator.

Expression Member function Non-member function
@a (a).operator@() operator@(a)
a@b (a).operator@(b) operator@(a,b)
a[b] (a).operator[](b)

Given the table above, operand a is of type T1, and operand b is of type T2. T1 must be of class or enumeration type, and T2 may be of any type including T1. The candidate set for operator resolution is constructed by the process:

  • If T1 is a class type, the result of qualified lookup of operator@ is added to the set.

  • The result of unqualified lookup of operator@ in the context of the expression excluding the results from step 1. If no operand is of class type, only functions where T1 or T2 are enumerations are added to the set.

  • The built-in operators of operator@ from the operators defined in [Overload.Builtin] are added to the set.

The left operand to built-in assignment operators, may not have user-defined conversion applied to it, and no temporary may be introduced to hold it.

If the operator is the comma (,) operator, and there are no viable functions, the built-in operator is used.

11.3.1.5 Initialization by Conversion[Overload.Res.Convert]

An object of class type or non-class type T may be initialized with an initializing expression of class type S invoking a user-defined conversion.

The candidate set of conversion functions will be the non-explicit conversion functions of S and its base classes.

The argument list has one argument which is the initializer expression.

11.3.2 Viable Functions[Overload.Res.Viable]

Given the candidate set and argument expressions as determined by the relevant context (11.3.1), a subset of viable functions can be selected from the candidate set.

A function candidate F(P0...Pm) is not a viable function for a call with argument list A0...An if:

  • The function has fewer parameters than there are arguments in the argument list (m < n).

  • The function has more parameters than there are arguments to the argument list (m > n), and function parameters Pn + 1...Pm do not all have default arguments.

  • There is not an implicit conversion sequence that converts each argument Ai to the type of the corresponding parameter Pi.

11.3.3 Best Viable Function[Overload.Res.Best]

For an overloaded call with arguments A0...An, each viable function F(P0...Pm), has a set of implicit conversion sequences ICS0(F)...ICSm(F) defining the conversion sequences for each argument Ai to the type of parameter Pi.

A viable function F is defined to be a better function than another viable function f′ if for all arguments ICSi(F) is not a worse conversion sequence than ICSi(f′), and:

  • for some argument j, ICSj(F) is a better conversion than ICSj(f′) or,

  • in the context of an initialization by user-defined conversion, the conversion sequence from the return type of F to the destination type is a better conversion sequence than the return type of f′ to the destination type or,

  • F is a non-template function and f′ is a function template specialization, or

  • F and f′ are both function template specializations and F is more specialized than f′ according to function template partial ordering rules ([Template.Func.Order]).

If there is one viable function that is a better function than all the other viable functions, it is the selected function; otherwise the call is ill-formed.

If the resolved overload is a function with multiple declarations, and if at least two of these declarations specify a default argument that made the function viable, the program is ill-formed.

void F(int X = 1); void F(float Y = 2.0f);

void Fn() F(1); // Okay. F(3.0f); // Okay. F(); // Ill-formed.

11.3.4 Implicit Conversion Sequences[Overload.ICS]

An implicit conversion sequence is a sequence of conversions which converts a source value to a prvalue of destination type. In overload resolution the source value is the argument expression in a function call, and the destination type is the type of the corresponding parameter of the function being called.

When a parameter is a cxvalue an inverted implicit conversion sequence is required to convert the parameter type back to the argument type for writing back to the argument expression lvalue. An inverted implicit conversion sequence must be a well-formed implicit conversion sequence where the source value is the implicit cxvalue of the parameter type, and the destination type is the argument expression’s lvalue type.

A well-formed implicit conversion sequence is either a standard conversion sequence, or a user-defined conversion sequence.

In the following contexts, an implicit conversion sequence can only be a standard conversion sequence:

  • Argument conversion for a user-defined conversion function.

  • Copying a temporary for class copy-initialization.

  • When passing an initializer-list as a single argument.

  • Copy-initialization of a class by user-defined conversion.

An implicit conversion sequence models a copy-initialization unless it is an inverted implicit conversion sequence when it models an assignment. Any difference in top-level cv-qualification is handled by the copy-initialization or assignment, and does not constitute a conversion.

NOTE "Top-level" cv-qualification refers to the qualification of the value. This means an parameter of type T can be initialized by a argument of type const T. This does not mean that a parameter of type inout T can be initialized with a argument of type const T because there is no valid inverted conversion system to assign back to a value of type const T.

When the source value type and the destination type are the same, the implicit conversion sequence is an identity conversion, which signifies no conversion.

Only standard conversion sequences that do not create temporary objects are valid for implicit object parameters or left operand to assignment operators.

If no sequence of conversions can be found to convert a source value to the destination type, an implicit conversion sequence cannot be formed.

If several different sequences of conversions exist that convert the source value to the destination type, the implicit conversion sequence is defined to be the unique conversion sequence designated the ambiguous conversion sequence. For the purpose of ranking implicit conversion sequences, the ambiguous conversion sequence is treated as a user-defined sequence that is indistinguishable from any other user-defined conversion sequence. If overload resolution selects a function using the ambiguous conversion sequence as the best match for a call, the call is ill-formed.

11.3.4.1 Standard Conversion Sequences[Overload.ICS.SCS]

The conversions that comprise a standard conversion sequence and the composition of the sequence are defined in Chapter 7.

Each standard conversion is given a category and rank as defined in the table below:

Conversion Category Rank Reference
No conversion Identity
1-2 Lvalue-to-rvalue Lvalue Transformation 7.1
Array-to-pointer Lvalue Transformation 7.2
1-2 Qualification Qualification Adjustment Exact Match 7.16
1-4 Vector Scalar splat (without conversion) 7.11
Matrix Scalar splat (without conversion) Scalar Extension Extension 7.12
1-4 Integral promotion 7.5 & 7.17.1
Floating point promotion 7.7 & 7.17.2
Component-wise promotion Promotion Promotion 7.15
1-4 Vector Scalar splat promotion 7.11
Matrix Scalar splat promotion Scalar Extension Promotion Promotion Extension 7.12
1-4 Integral conversion 7.5
Floating point conversion 7.7
Floating-integral conversion 7.8
Boolean conversion 7.9
Component-wise conversion Conversion Conversion 7.15
1-4 Scalar splat conversion 7.11
Vector Scalar splat conversion 7.11
Matrix Scalar splat conversion Scalar Extension Conversion Conversion Extension 7.12
1-4 Vector truncation (without conversion) 7.14
Matrix truncation (without conversion) Dimensionality Reduction Truncation 7.14
1-4 Vector truncation promotion 7.14
Matrix truncation promotion Dimensionality Reduction Promotion Promotion Truncation 7.14
1-4 Vector truncation conversion 7.14
Matrix truncation conversion Dimensionality Reduction Conversion Conversion Truncation 7.14
1-4

If a scalar splat conversion occurs in a conversion sequence where all other conversions are Exact Match rank, the conversion is ranked as Extension. If a scalar splat occurs in a conversion sequence with a Promotion conversion, the conversion is ranked as Promotion Extension. If a scalar splat occurs in a conversion sequence with a Conversion conversion, the conversion is ranked as Conversion Extension.

If a vector or matrix truncation conversion occurs in a conversion sequence where all other conversions are Exact Match rank, the conversion is ranked as Truncation. If a vector or matrix truncation occurs in a conversion sequence with a Promotion conversion, the conversion is ranked as Promotion Truncation. If a vector or matrix truncation occurs in a conversion sequence with a Conversion conversion, the conversion is ranked as Conversion Truncation.

Otherwise, the rank of a conversion sequence is determined by considering the rank of each conversion.

Conversion sequence ranks are ordered from better to worse as:

  • Exact Match

  • Extension

  • Promotion

  • Promotion Extension

  • Conversion

  • Conversion Extension

  • Truncation

  • Promotion Truncation

  • Conversion Truncation

11.3.4.2 User-defined Conversion Sequences[Overload.ICS.User]

A user-defined conversion sequence is a standard conversion sequence followed by a user-defined conversion, followed by a second standard conversion sequence.

The first standard conversion sequence converts the source type to the type of the object parameter of the conversion function of the user-defined conversion.

The second standard conversion converts the result of the user-defined conversion to the target type for the conversion sequence.

If the user-defined conversion is a template specialization, the second standard conversion sequence shall have the rank Exact Match.

If the user-defined conversion specifies a conversion from a class type to the same class type, it shall have the rank Exact Match even if a conversion function is invoked and it produces temporaries or other side-effects.

If the user-defined conversion converts from a class type to a base class of that type, it shall have the rank Conversion even if a conversion function is invoked and it produces temporaries or other side-effects.

11.3.4.3 Comparing Implicit Conversion Sequences[Overload.ICS.Comparing]

A partial ordering of implicit conversion sequences exists based on defining relationships for better conversion sequence, and better conversion. If an implicit conversion sequence ICS(f) is a better conversion sequence than ICS(f′), then the inverse is also true: ICS(f′) is a worse conversion sequence than ICS(f). If ICS(f) is neither better nor worse than ICS(f′), the conversion sequences are indistinguishable conversion sequences.

A standard conversion sequence is always better than a user-defined conversion sequence.

Standard conversion sequences are ordered by their ranks. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:

  • If class B is derived directly or indirectly from class A and class C is derived directly or indirectly from class B,

  • binding of a expression of type C to a cxvalue of type B is better than binding an expression of type C to a cxvalue of type A,

  • conversion of C to B is better than conversion or C to A,

  • binding of a expression of type B to a cxvalue of type A is better than binding an expression of type C to a cxvalue of type A,

  • conversion of B to A is better than conversion of C to A.

11.4 Overloaded Operators[Overload.Operators]

operator-function-id:
operator operator

operator: one of
+ - * / % ^ & |   ! < > << >> <= >= && || ,

The operators +, -, , and & may only be overloaded in their binary form.

The dot (.), :: and ?: operators cannot be overloaded.

Operator functions may be called directly by their name in the form operator@ or through the resolution of an overload from an operator expression.

An overloaded operator function must be either a non-static member function or a non-member function, and must have at least one parameter whose type is a class or enumeration.

An overloaded operator may not change the number of operands of an operator, except the function call operator which may have any number of operands.

The meaning of the comma (,) operator, which is pre-defined for all types, can be changed by operator overloading.

Overloaded operator functions are inherited from base classes in the same way as other base class member functions.

Only an overloaded call operator may have default arguments, no other operator functions may be defined with default arguments. All operator functions must take exactly the number of parameters of the corresponding operator as defined in this subclause.

11.4.1 Unary Operators[Overload.Operators.Unary]

An overloaded prefix unary operator must be implemented by a non-static member function with no parameters or a non-member function with one parameter.

Postfix unary operators are not overloadable.

11.4.2 Binary Operators[Overload.Operators.Binary]

An overloaded binary operator must be implemented by a non-static member function with one parameter or a non-member function with two parameters.

11.4.3 Function Call Operator[Overload.Operators.Call]

An overloaded function call operator must be a non-static member function with an arbitrary number of parameters, and may have default arguments. Function call operator functions are overload candidates for the function call syntax when the postfix-expression is an object of class type.

11.4.4 Subscript Operator[Overload.Operators.Subscript]

An overloaded subscript operator must be a non-static member function with one parameter. Subscript operator functions are overload candidates for the subscript syntax when the postfix-expression is an object of class type.

11.4.5 Built-in Operators[Overload.Operators.BuiltIn]

For binary operators on arithmetic types, the result type is called the promoted expression type as determined by usual arithmetic conversions (8.1).

For all types T where T is an arithmetic type (6.9.1); operators will be defined of the forms:

T operator+(T ); T operator-(T ); T operator (T );

For all types L, R and LR, where L and R are any arithmetic type (6.9.1), and LR is the promoted expression type; operators will be defined of the forms:

LR operator*(L , R ); LR operator/(L , R ); LR operator+(L , R ); LR operator-(L , R ); bool operator<(L , R ); bool operator>(L , R ); bool operator<=(L , R ); bool operator>=(L , R ); bool operator==(L , R ); bool operator!=(L , R ); LR operator

For all types T where T is an enumeration type ([Decl.Enum]); operators will be defined of the form:

bool operator<(T , T ); bool operator>(T , T ); bool operator<=(T , T ); bool operator>=(T , T ); bool operator==(T , T ); bool operator!=(T , T );

For all types T where T is an integral type (6.9.1); operators will be defined of the form:

LR operator&(L , R ); LR operator^(L , R ); LR operator|(L , R ); L operator<<(L , R ); L operator>>(L , R );

For all types L and R where L and R are arithmetic types (6.9.1), and CVQ is a cv-qualifier; operators will be defined of the form:

CVQ L & operator=(CVQ L &, R ); CVQ L & operator*=(CVQ L &, R ); CVQ L & operator/=(CVQ L &, R ); CVQ L & operator+=(CVQ L &, R ); CVQ L & operator-=(CVQ L &, R ); CVQ L & operator

For all types L and R where L and R are integral types (6.9.1), and CVQ is a cv-qualifier; operators will be defined of the form:

CVQ L & operator<<=(CVQ L &, R ); CVQ L & operator>>=(CVQ L &, R ); CVQ L & operator&=(CVQ L &, R ); CVQ L & operator^=(CVQ L &, R ); CVQ L & operator|=(CVQ L &, R );

For the boolean type bool operators will be defined of the form:

bool operator!(bool); bool operator&&(bool, bool); bool operator||(bool, bool);

For all types L, R and LR, where L and R are any arithmetic type (6.9.1), and LR is the promoted expression type; the ternary operator will be defined of the form:

LR operator?:(bool, L , R );

For all types T, a ternary operator will be defined of the form:

T operator?:(bool, T , T );