It's useful to consider examples. When you have:
struct C {
void f(int);
void f(int) const;
};
C c;
c.f(42);
How does overload resolution pick? You effectively have a choice of:
// implicit object | regular
// parameter | parameter
void f(C&, int );
void f(C const&, int );
With the arguments (C, int)
. That ends up picking the first one, for being a better match.
Now, let's think of this example:
struct D {
static void g(int);
void g(long);
};
D d;
d.g(42);
Now, if we try to do the same thing:
// implicit object | regular
// parameter | parameter
void g(????????, int );
void g(D&, long );
We have two arguments, a D
and an int
. We don't know if we're going to call a static function or not yet, we still have to do overload resolution. How do we pick in this case? The non-static member function has an implicit object parameter, D&
, but what do we do for the static one?
The C++ answer is we contrive a fake parameter, that is a perfect match for everything:
// implicit object | regular
// parameter | parameter
void g(contrived-match, int );
void g(D&, long );
And now, when we do overload resolution with (D, int)
, you can see that the static function is the best match (better conversion sequence for the second parameter).
Once we pick the static member function, we then ignore the object argument entirely. d.f(42)
basically evaluates as D::f(42)
. But we didn't know that until we performed overload resolution - the contrived parameter exists to solve the problem of how to actually compare these cases.
This still applies even if there were just the one static member function - since d.f(42)
does have two parameters: the d
and the 42
, so the language needs to handle the d
somehow (the alternative could've been to simply disallow this syntax, requiring D::f(42)
if you wanted to call a static member function, but that seems a lot less nice).
this
pointer. But, in all C++ standards since 1998, the standard requires that both static and non-static member functions receive an implicit object parameter for purposes of overload resolution. Among other things, that's why - ifsome_object
is an instance ofX
- the syntaxsome_object.function()
can be used to callX::function()
even iffunction()
is a static member function ofX
. – Deplume