I wrote the following program in c++23. Here I’ve overloaded member functions. But for all cases different compilers give different result as shown below in comment. As you can see I have three cases below. Demo.
struct C {
void j(this const C);
void j() const ; //#1: Clang:Nope while gcc and msvc:Ok
// void f(this C );
// void f(C); //#2: EDG: Nope while Clang,gcc and msvc:OK
// void k(this const C&);
// void k() const ; //#3: EDG: OK while Clang, gcc and msvc:Nope
};
I want to know what is the standard conformant behavior for the three cases.
#1
is accepted by gcc and msvc but rejected by clang saying:
<source>:3:10: error: class member cannot be redeclared
3 | void j() const ; //#1: Clang:Nope while gcc and msvc:Ok
| ^
<source>:2:10: note: previous declaration is here
2 | void j(this const C);
|
11
tldr; #1
and #3
are ill-formed while #2
is well-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 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
Now let’s apply this to our examples one by one:
Case #1
Here we consider the overloads:
void j(this const C);
void j() const;
Here exactly one of the declarations is an implicit object member function with no ref-qualifier and the type of their object parameter after removing the reference is same(which is just const C
after removing reference).
Thus these have corresponding object parameters.
Now as per basic.scope.scope#4.4 quoted above, these are corresponding overloads because they both declare functions with the same non-object-parameter-type-list and they have corresponding object parameters.
Thus #1
is ill-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 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.
1