C++ Overload Static Function with Non-Static Function

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 a static 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 class X may be
referred to using the qualified-id
expression X::s; it is not necessary
to use the class member access syntax
(5.2.5) to refer to a static member. A
static member may be referred to using
the class member access syntax, in
which case the object-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 keyword this 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 function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(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 that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(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 than ICSj(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 and F2 is a function template specialization, or, if not that,

Nope.

  • F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,

Nope.

  • F1 and F2 are non-template functions with the same parameter-type-lists, and F1 is more constrained than F2 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



Leave a reply



Submit