Overloading[Overload]

8 Overloading[Overload]

HLSL inherits much of its overloading behavior from C++. This chapter is extremely similar to isoCPP clause [over]. Notable differences exist around HLSL’s parameter modifier keywords, program entry points, and overload conversion sequence ranking.

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 template declarations can be overloaded; variable and type declarations cannot be overloaded.

8.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.

In 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 (10.1).

    class Doggo

    static void pet(); void pet(); // ill-formed: static pet has the same parameter-type-list void pet() const; // ill-formed: static pet has the same parameter-type-list

    void wagTail(); // valid: no conflicting static declaration. void wagTail() const; // valid: no conflicting static declaration.

    static void bark(Doggo D); void bark(); // valid: static bark parameter-type-list is different void bark() const; // valid: static bark parameter-type-list is different

    ;

  • An overload set contains more than one entry function declaration (7.6.2).

    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 parameter declarations of equivalent types.

    void F(int4 I); void F(vector<int, 4> I); // ill-formed: int4 is a type alias of vector<int, 4>

  • An overload set contains more than one function declaration which only differ in const 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

8.2 Overload Resolution[Overload.Res]

Overload resolution is process by which a function call is mapped to a the best overloaded function declaration. Overload resolution uses 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 contexts1:

  • 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 for copy-initialization of a class object;

  • invocation of a conversion function for initialization of an object of a nonclass 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.

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

isoCPP goes into a lot of detail in this section about how candidate functions and argument lists are selected for each context where overload resolution is performed. HLSL matches C++ for the contexts that HLSL inherits. For now, this section will be left as a stub, but HLSL inherits the following sections from C++:

  • [over.call.func]

  • [over.call.object]

  • [over.match.oper]

  • [over.match.copy]

  • [over.match.conv]

8.2.2 Viable Functions[Overload.Res.Viable]

Given the candidate set and argument expressions as determined by the relevant context (8.2.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.

8.2.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 $ICS_i(F`)$, and:

  • for some argument j, ICSj(F) is a better conversion than $ICS_j(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 (11.2).

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.

8.2.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 conversion2.

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.

8.2.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 4.

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

4.1
4-4 Array-to-pointer Lvalue Transformation Exact Match 4.2
1-2 Qualification Qualification Adjustment 4.15

1-4

Vector Scalar splat conversion

Scalar Extension Conversion Conversion Extension 4.10

1-4

Matrix Scalar splat conversion

Scalar Extension Conversion Conversion Extension 4.11

1-4

Integral promotion

4.5 & 4.16.1
1-1 Floating point promotion Promotion Promotion 4.6 & 4.16.2
1-1 Component-wise promotion 4.14

1-4

Scalar splat promotion

Scalar Extension Promotion Promotion Extension 4.10

1-4

Integral conversion

4.5
1-1 Floating point conversion 4.6
1-1 Floating-integral conversion Conversion Conversion 4.7
1-1 Boolean conversion 4.8
1-1 Component-wise conversion 4.14

1-4

Scalar splat conversion

Scalar Extension Conversion Conversion Extension 4.10

1-4

Vector truncation (without conversion)

Dimensionality Reduction Truncation 4.13

1-4

Vector truncation promotion

Dimensionality Reduction Promotion Promotion Truncation 4.13

1-4

Vector truncation conversion

Dimensionality Reduction Conversion Conversion Truncation 4.13

1-4

Matrix truncation (without conversion)

Dimensionality Reduction Truncation 4.13

1-4

Matrix truncation promotion

Dimensionality Reduction Promotion Promotion Truncation 4.13

1-4

Matrix truncation conversion

Dimensionality Reduction Conversion Conversion Truncation 4.13
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 truncation conversion occurs in a conversion sequence where all other conversions are Exact Match rank, the conversion is ranked as Truncation. If a vector truncation occurs in a conversion sequence with a Promotion conversion, the conversion is ranked as Promotion Truncation. If a vector 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:

  1. Exact Match

  2. Extension

  3. Promotion

  4. Promotion Extension

  5. Conversion

  6. Conversion Extension

  7. Truncation

  8. Promotion Truncation

  9. Conversion Truncation

8.2.4.2 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.