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.