C++ Overload Static Function with Non-Static Function
No, it is directly prohibited by the standard:
ISO 14882:2003 C++ Standard 13.1/2 – Overloadable declarations
Certain function declarations cannot
be overloaded:
- Function declarations that differ only in the return type cannot be overloaded.
- Member function declarations with the same name and the same parameter types cannot be overloaded
if any of them is astatic
member function declaration (9.4).
...
[Example:
class X {
static void f();
void f(); // ill-formed
void f() const; // ill-formed
void f() const volatile; // ill-formed
void g();
void g() const; // OK: no static g
void g() const volatile; // OK: no static g
};
—end example]
...
Besides, it would be ambiguous anyway since it's possible to call static functions on instances:
ISO 14882:2003 C++ Standard 9.4/2 – Static members
A static member
s
of classX
may be
referred to using the qualified-id
expressionX::s
; it is not necessary
to use the class member access syntax
(5.2.5) to refer to astatic member
. A
static
member may be referred to using
the class member access syntax, in
which case theobject-expression
is
evaluated. [Example:
class process {
public:
static void reschedule();
}
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
—end example]
...
So there would be ambiguity with what you have:
class Foo
{
public:
string bla;
Foo() { bla = "nonstatic"; }
void print() { cout << bla << endl; }
static void print() { cout << "static" << endl; }
};
int main()
{
Foo f;
// Call the static or non-static member function?
// C++ standard 9.4/2 says that static member
// functions are callable via this syntax. But
// since there's also a non-static function named
// "print()", it is ambiguous.
f.print();
}
To address your question about whether you can check what instance a member function is being called on, there is the this
keyword. The this
keyword points to the object for which function was invoked. However, the this
keyword will always point to an object i.e. it will never be NULL
. Therefore it's not possible to check if a function is being called statically or not à la PHP.
ISO 14882:2003 C++ Standard 9.3.2/1 – The this pointer
In the body of a nonstatic (9.3)
member function, the keywordthis
is a
non-lvalue expression whose value is
the address of the object for which
the function is called.
Why does function overload resolution in C++ consider non-static member functions for static calls?
Why can't the compiler simply choose
static void foo(int a, float b)
?
My understanding of your questions is that you assume the syntax A::foo
is unambiguous due to the non-instance A::
prefix. But have a look at this scenario:
struct A {
static void foo(int, float);
void foo(float, int);
};
struct B : A {
// Hide the base class foo
void foo()
{
// Now explicitly call it... this is ambiguous!
A::foo(1.f, 1.f);
}
};
Hence, the A::
prefix can refer to both static
and non-static
member functions, depending on the context. The compiler can't assume that it's referring to a static
member function only.
There are more scenarios where a qualified non-static
member function call like A::foo
is necessary, e.g. in a diamond inheritance structure (if you don't use virtual
inheritance). This is why any member function can be invoked like this (even when it's unnecessary and doesn't make sense: A a; a.A::foo(1, 2.f);
.
Overloading static and non-static member function with constraint
If we go through [over.match.best.general], we get:
a viable function
F1
is defined to be a better function than another viable functionF2
if for all argumentsi
,ICSi(F1)
is not a worse conversion sequence thanICSi(F2)
, and then [...]
The only argument is the object argument, and we have earlier that:
If
F
is a static member function,ICS1(F)
is defined such thatICS1(F)
is neither better nor worse thanICS1(G)
for any functionG
, and, symmetrically,ICS1(G)
is neither better nor worse thanICS1(F)
; otherwise,
So the premise holds: all arguments for one function have a conversion sequence no worse than the conversion sequence for the other function. So we move on to our tiebreakers...
- for some argument
j
,ICSj(F1)
is a better conversion sequence thanICSj(F2)
, or, if not that,
The only argument that we could have a better conversion sequence for is the object argument, and as established, that one is equivalent. So this tiebreaker does not apply.
- the context is an initialization by user-defined conversion (see [dcl.init], [over.match.conv], and [over.match.ref]) and [...]
Nope.
- the context is an initialization by conversion function for direct reference binding of a reference to function type, [...]
Nope.
F1
is not a function template specialization andF2
is a function template specialization, or, if not that,
Nope.
F1
andF2
are function template specializations, and the function template forF1
is more specialized than the template forF2
according to the partial ordering rules described in [temp.func.order], or, if not that,
Nope.
F1
andF2
are non-template functions with the same parameter-type-lists, andF1
is more constrained thanF2
according to the partial ordering of constraints described in [temp.constr.order], or if not that,
Aha! In this example, we have non-template functions with the same parameter-type-lists (both are just empty). The static member function is constrained and the non-static member function is not constrained, which is the most trivial kind of "more constrained" (see [temp.constr.order]).
As such, I think that clang (and msvc) are correct to accept the program and gcc is incorrect to reject it. (submitted 103783).
Why can't a static and non-static method share the same signature?
Reason why it is throwing an error is that static methods can be called from non-static methods without specifying type name. In this case, compiler won't be able to determine, which method is being called.
public class Foo()
{
public static void MyMethod() {};
public void MyMethod() {}
public void SomeOtherMethod()
{
MyMethod(); // which method we're calling static or non-static ?
}
}
EDIT
Just found this SO post regarding your case. You might want to check it also.
c++ static member function overloading with inheritance
Here you go:
struct Derived : CommonHandler, AnotherHandler
{
using CommonHandler::foo;
using CommonHandler::bar;
using AnotherHandler::foo;
using AnotherHandler::bar;
};
Fixes your problem.
The reason for original code not working is found in C++ standard. Here are interesting quotes:
In 10/2:
The base class members are said to be inherited by the derived class.
Inherited members can be referred to in expressions in the same manner
as other members of the derived class, unless their names are hidden
or ambiguous (10.2).
Continuing reading to 10.2:
Member name lookup determines the meaning of a name (id-expression) in
a class scope (3.3.7). Name lookup can result in an ambiguity, in
which case the program is ill-formed.......consists of two component sets: the declaration set, a
set of members named f...If the name of an overloaded function is unambiguously found, overloading resolution (13.3) also takes place before access control
Basically, it goes by name first and applies resolution later. Introducing them to derived class through using
declaration puts them all in the scope of derived class, where normal resolution rules kick-in.
Method overloading with both static and non-static methods
Use of keyword static
doesn't make a difference in method overloading.
Your code compiles because the method signature of both add()
methods are different (2 params vs 3 params).
However, if you were to write something like this, then it would result in a compilation error.
class Adder {
static int add(int a, int b) {
return a + b;
}
int add(int a, int b) {
return a + b;
}
}
Related Topics
Linking Fortran and C++ Binaries Using Gcc
Why Does C++ Need the Scope Resolution Operator
Lightweight Memory Leak Debugging on Linux
Gcc Style Weak Linking in Visual Studio
While (1) VS. for (;;) Is There a Speed Difference
C++ High Precision Time Measurement in Windows
How to Enable C++11 in Qt Creator
Iterating Over a Struct in C++
How to Find What Version of Libstdc++ Library Is Installed on Your Linux MAChine
Is 'Long' Guaranteed to Be at Least 32 Bits
Returning Temporary Object and Binding to Const Reference
What Exactly Is the L Prefix in C++
How to Increase Thread Priority in Pthreads