10

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.

yuri kilochek
  • 11,212
  • 2
  • 25
  • 52
  • 1
    You might need to ask Bjarne Stroustrup! – peacemaker Jul 27 '12 at 21:47
  • 1
    Searching like this means that the list of candidate functions generated is always small. That's good for compile times, you can imagine if it searched all possible candidates (including ADL) and there were many templates it would very quickly get very slow. It also mirrors usage and desired semantics in most cases. Normally when you say `foo` the `foo` you're thinking of is the closest one. If it's not the closest one it's likely to just made a mistake. An error is better than weird stuff happening at run time. Keeping things local is good behaviour. – Flexo Jul 27 '12 at 21:48
  • 2
    you may enjoy this presentation on Name Lookup: http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/Stephan-T-Lavavej-Core-C-1-of-n – MFH Jul 27 '12 at 21:50
  • This is ordinary *name hiding* at work. So the answer will depend on what kind of "why" you are implying. The immediate "why" is "because that's how name lookup works in C++". As for "why" the language was designed that way... well, D&E might have the answer, although name hiding exists in C as well. – AnT Jul 27 '12 at 22:18
  • @AndreyT "_This is ordinary name hiding at work._" It is ordinary in other languages, but not in C++. There is a special rule for member names. – curiousguy Aug 16 '12 at 17:47
  • @Flexo "_you're thinking of is the closest one._" close how? Which distance? – curiousguy Aug 16 '12 at 18:05

3 Answers3

7

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.

Xeo
  • 123,374
  • 44
  • 277
  • 381
  • 1
    "_The problem is that name lookup doesn't concern itself with anything but the name, the identifier._" In almost all languages, that is true. Not in C++. – curiousguy Aug 16 '12 at 17:51
3

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.

curiousguy
  • 7,344
  • 2
  • 37
  • 52
  • This is not as crazy as you may think. Name lookup stops when a match is found (stated somewhere around §3.4 or so), and a precise order is given from the inside outwards. So if a member with a name is found, it stops. No surprise. – Damon May 04 '15 at 14:52
  • @Damon "_Name lookup stops when a match is found_" does not, as my second `swap` call shows – curiousguy May 05 '15 at 00:29
2

I cannot provide an authoritative answer (Maybe some remember a quote from Design and Evolution of C++ or actually has been on the committee at that time), but my first guess would be to exactly fail in cases as you show. It is easy to forget how many things are in scope at a certain time. Additionally overload resolution can be quite complex and there can be default arguments and conversion. So I'd rather have the most limited scope in that case to be always sure what exactly is being called.

pmr
  • 54,366
  • 9
  • 104
  • 149
  • Speculation, but that's my hunch too. It's hard to distinguish between relying on crazy far flung searches and typos. – Flexo Jul 27 '12 at 21:51
  • "_It is easy to forget how many things are in scope at a certain time._" this is an extremely strong argument for not doing name hiding here. – curiousguy Aug 16 '12 at 17:54