Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

class static member function chosen over global function with same name?

Doubt originated from here


int g() {
   cout << "In function g()" << endl;
   return 0;
}

class X {
public:
  static int g() {
     cout << "In static member function X::g()" << endl;
     return 1;
  }
};

class Y: public X {
   public:
  static int i;
};

int Y::i = g();   

initially I though that as symbol resolution happens from inner most scope to outer most scope, that is why x::g() would be called.
but then I closely noticed the code

int Y::i = g();

how are we able to access X::g() without namescope?
And scope in which this statement lies should be global, not Y:: or X:: , so symbol resolution should give global version of the function g()?

like image 353
Amar Avatar asked Apr 29 '11 08:04

Amar


2 Answers

Note: I think my earlier answer was wrong. Its not Koenig Lookup i.e Argument-dependent name lookup (ADL). So I deleted my (earlier) answer since I found the relevant section from the Standard which answers your question.

Your code is directly from the section §9.4/2 of the C++03 Standard.

A static member may be referred to directly in the scope of its class or in the scope of a class derived (clause 10) from its class; in this case, the static member is referred to as if a qualified-id expression was used, with the nested-name-specifier of the qualified-id naming the class scope from which the static member is referenced.

It then gives this example (which you've asked in the question)

[Example:

    int g();
    struct X {
        static int g();
    };
    struct Y : X {
        static int i;
    };
    int Y::i = g(); // equivalent to Y::g();

—end example]

It then says that in §9.4/3

If an unqualified-id (5.1) is used in the definition of a static member following the member’s declarator-id, and name lookup (3.4.1) finds that the unqualified-id refers to a static member, enumerator, or nested type of the member’s class (or of a base class of the member’s class), the unqualified-id is transformed into a qualified-id expression in which the nested-name-specifier names the class scope from which the member is referenced.

Since that happens only in the definition of the static member, that means Y::g() is called ONLY in the initialization, not in assignment:

//definition-cum-initialization
int Y::i = g(); // equivalent to Y::g();
int main()
{
   //assignment 
   Y::i = g(); // does not equivalent to Y::g(); it calls global g()
}

See the output here : http://www.ideone.com/6KDMI

Lets consider another example:

struct B{};

B f();

namespace NS 
{
   struct A { static B b;};
   B f();
}

//Definition cum Initialization
B NS::A::b = f();  //calls NS::f()
B b = f();         //calls global f()

int main() 
{
   //Assignment
   NS::A::b = f(); //calls global f()
   b = f();        //calls global f()
}

See the complete demo here : http://www.ideone.com/53hoW

like image 99
Nawaz Avatar answered Nov 15 '22 05:11

Nawaz


This is because you use int Y::i =..., note the Y::. That's why, it actually looks for g() inside Y, which is X::g(), because Y derives X.


Addition: For example, if you put int i = g(); after int Y::i = g();, there result would be:

In static member function X::g()
In function g()

EDIT: exactly - Argument-dependent name lookup. I couldn't remember how this is called at the beginning. Thanks Nawaz's answer (:

EDIT2: OK, Nawaz found the correct explanation, it's in the standard and it seems not to be "Argument-dependent name lookup". But the logic is still absolutely the same.

like image 35
Kiril Kirov Avatar answered Nov 15 '22 05:11

Kiril Kirov