According to cppreference since C++23
For a non-static non-virtual member function not declared with cv-qualifier or ref-qualifier, its first parameter, if not being a function parameter pack, can be an explicit object parameter (denoted with the prefixed keyword
this
).
Can this parameter be of type void
? Current compilers allow it, but diverge in calling of such member function:
struct A {
void f(this void) {}
};
// ok everywhere
auto p = &A::f;
int main() {
// ok in GCC and MSVC
p();
// ok in Clang
A{}.f();
}
Clang rejects p();
with the
error: called object type 'void (A::*)()' is not a function or function pointer
And GCC does not like A{}.f();
because
note: candidate expects -1 arguments, 0 provided
As well as MSVC:
error C2660: 'A::f': function does not take 0 arguments
Online demo: https://gcc.godbolt.org/z/zMaqaTTav
Which compiler is correct here?
The way the standard is currently written I would tend to say that Clang is the one behaving correctly.
According to [dcl.fct]/3:
A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
The this
keyword does not affect the type of the parameter which is still void
and it remains unnamed. Since it isn't inside a template, it is trivially not dependent either.
The rest of [dcl.fct] assumes that this adjustment of the declaration has been made without mentioning it explicitly again, for example when defining the type of a function in [dcl.fct]/5.
Therefore I think [dcl.fct]/6 which specifies the effect of this
in the parameter declaration to declare an explicit object parameter should also be considered after the void
-adjustment.
Then, since the this void
parameter declaration was removed from the list, the function is not an explicit object function, but an implicit object function without any parameters.
The function's type will be void()
and &A::f
then forms a member pointer of type void (*A::f)()
. Calling the member pointer with function call syntax p()
is not possible.
Calling the non-static member function with a member access expression A{}.f()
is however possible. this
in the function definition will point to the temporary object materialized from A{}
. No call arguments are needed because f
has no parameters.
However, I am not sure whether this is actually the desirable behavior. The special adjustment of [dcl.fct]/3 exists only for C backwards-compatibility. There is no need to extend it to this void
which isn't valid in C anyway. Instead I would think it should be made ill-formed like all other uses of (cv-qualified) void
parameters.
The behavior of GCC and MSVC doesn't make sense either way. Even if this void
still caused the function to be an explicit object function and wasn't ill-formed, then, whether or not this void
is considered an actual parameter, the rest of the standard's specifications wouldn't be consistent. Either this would be an explicit object function without an explicit object parameter which is however required to be initialized in calls. Or it would be a function with a void
parameter that needs to be initialized, but void
objects do not exist in the first place.