Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why class member functions shadow free functions with same name?

It recently came to my attention that member functions completely shadow free functions with the same name when inside the class. And by completely I mean that every free function with the same name is not considered for overload resolution at all. I can understand why it's done with something like this:

void f();

struct S
{
    void f();

    void g()
    {
        f(); // calls S::f instead of ::f
    }
};

where the functions have identical signatures, its only natural as variable scoping works the same way. But why prohibit unambigious calls where free function has different signature like this:

void f();

struct S
{
    void f(int x);

    void g()
    {
        f(); // fails to compile attempting to call S::f, which has wrong signature
    }
};

I am not asking how to call a shadowed free function from inside the class. What i want to know is the rationale behind this design.

like image 355
yuri kilochek Avatar asked Jul 27 '12 21:07

yuri kilochek


2 Answers

For unqualified name lookup, only one scope at a time is considered, and if the search in that scope doesn't yield any results, the next higher scope is searched. In your case, only S's scope is searched.

But why prohibit unambigious calls where free function has different signature like this:

The problem is that name lookup doesn't concern itself with anything but the name, the identifier. It is completely oblivious to the fact that you want to call a function, it just sees an identifier. The same name lookup happens if you just use auto x = f;, and if you think of it that way, there are very good reasons you only want a very limited scope to search. Anything else would just surprise the user.

like image 102
Xeo Avatar answered Oct 22 '22 10:10

Xeo


There is a special, very surprising, rule (but it does not apply to your example) stating that once a class member name is found by name lookup, no namespace scopes are searched:

#include <string>

struct C {
    std::string s;

    explicit C (std::string);

    void swap (C& rhs) {
        swap (s, rhs.s); // error: swap is C::swap
    }   
};

void swap (C& lhs, C& rhs) {
    swap (lhs.s, rhs.s); // std::swap(string,string)
}

IMO, this is craziness.

But why prohibit unambigious calls where free function has different signature like this:

Name lookup happens before overloading resolution:

  • If lookup is ambiguous, overloading resolution is not done.
  • If no viable function is found by name lookup, no other round of lookup is tried.

The rules are sufficiently complex without "feedback" between overloading and name lookup. I would suggest simplification (like removing the member hides namespace scope name rule, and removing ambiguous name lookup) rather than complexification.

like image 32
curiousguy Avatar answered Oct 22 '22 10:10

curiousguy