tldr; #1
and #2
are well-formed while #3
is ill-formed for the reasons explained below.
The behavior of the program can be understood using basic.scope.scope#3 and basic.scope.scope#4.4 and additionally dcl.fct#4 that states:
Two non-static member functions have corresponding object parameters if:
- exactly one is an implicit object member function with no ref-qualifier and the types of their object parameters ([dcl.fct]), after removing top-level references, are the same, or
- their object parameters have the same type.
Two function or function template declarations declare corresponding overloads if:
- both declare functions with the same non-object-parameter-type-list,17 equivalent ([temp.over.link]) trailing requires-clauses (if any, except as specified in [temp.friend]), and, if both are non-static members, they have corresponding object parameters, or
The type of a function is determined using the following rules.
The type of each parameter (including function parameter packs) is determined from its own parameter-declaration ([dcl.decl]).
After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”.
After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function's parameter-type-list.
Now let's apply this to your code snippets one by one:
Case #1
Here we consider the overloads:
void j(this const C);
void j() const;
Here the first overload has a top-level const
which is ignored/deleted as per dcl.fct#4.4. This means that it's explicit object parameter has type C
(after removal of const
). Next, the second overload has object parameter of type const C
(after removal of reference). This means that neither of basic.scope.scope is satisfied.
Thus these two don't have corresponding object parameters.
Now as per basic.scope.scope#4.4 these two overloads are not corresponding overloads.
Thus #1
is well-formed.
Case #2
Here we consider the overloads:
void f(this C );
void f(C);
This is well-formed because even though the type of their object parameters after removing reference is same(C
), their non-object-parameter-type-list are different. Thus, basic.scope.scope4.4 is violated which means in this case, these are not corresponding-overloads.
Thus, #2
is well-formed.
Case #3
Here we consider the overloads:
void k(this const C&);
void k() const
This is also ill-formed because exactly one of them is an implicit object member function with a corresponding object parameter of same type const C
after removing the reference. And hence these are corresponding overloads.
Thus, #3
is also ill-formed.