12

I'm confused by this situation and googling didn't give me the answer. Basically I have the following simple code that doesn't compile:

#include <iostream>

class A
{
public:
    int a(int c = 0) { return 1; }
    static int a() { return 2; }
};

int main()
{
    std::cout << A::a() << std::endl;
    return 0;
}

In compiling this, GCC 4.2 says the call to A::a() in main() is ambiguous with both versions of a() valid candidates. Apple's LLVM compiler 3.0 compiles with no error.

Why is gcc confused about which function I want to call? I thought it was obvious that by qualifying a() with A:: I'm asking for the static version of the function. Naturally this code still doesn't compile if I remove the static function a(), because A::a() is not valid syntax for calling the non-static a().

Thanks for any comment!

AusCBloke
  • 18,014
  • 6
  • 40
  • 44
fang
  • 199
  • 9
  • BTW, quick google search by me: "Name resolution of static and non-static member functions C++" came up with another SO question:http://stackoverflow.com/questions/5365689/c-overload-static-function-with-non-static-function – Bingo Feb 25 '12 at 23:28
  • oops my google-fu failed me... – fang Feb 25 '12 at 23:50

2 Answers2

6

The reason for this is because C++ specifies that this is ambiguous. Overload resolution specifies that for A::a, since this is not in scope, the argument list in that call is augmented by a contrived A object argument, instead of *this. Overload resolution does not exclude non-static member functions, but instead

If the argument list is augmented by a contrived object and overload resolution selects one of the non-static member functions of T, the call is ill-formed.

This has recently been subject of extensive discussion both in the committee in context of core issue 1005. See core issue 364 which considered changing this rule but didn't do so.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Thanks for the reference. However I'm still struggling to understand, why "overload resolution selects one of the non-static member functions of T". If I understand what you said right, the non-static a() has two arguments: this, and argument with default value (c = 0). The static a() has a "contrived A object argument". Because I'm not supplying a "this" pointer in the call, why would the non-static version be selected? – fang Feb 25 '12 at 23:48
  • No, `this` is not an argument in this call because there is no `this` in scope. That's the reason we pass a "contrived A object argument" in our call. Both of those functions have a implicit object parameter (for static functions that parameter is used only to receive the contrived A object argument). The non-static `a`'s implicit object parameter has type `A&` in your case (`A const&` in const member fncs). The contrived object argument in call `A::a()` matches both implicit object parameters, so you have an ambiguity. – Johannes Schaub - litb Feb 26 '12 at 00:00
  • So this "contrived A object argument" is the same type as *this? – fang Feb 26 '12 at 00:03
  • @fang see in the spec at 13.3.1.1.1p3 and 13.3.1 – Johannes Schaub - litb Feb 26 '12 at 00:05
3

The reason is name resolution happens before anything else the compiler does, like figuring out which overloaded function to use.

Qualifying the function with A:: simply tells the compiler to "look inside of A to find the name a". It doesn't actually help resolve which function you are referring to.

EDIT

And so when you type A::a(), first the compiler thinks "look in A for a member function or member who can use operator()".

Then the compiler thinks, "Ok, two possibilities here, which one is being referred to? a() or a(int c = 0) with a default c=0. Not sure.

If you removed the static keyword and called the functions like obj.a(), there would still be an ambiguity.

WRT LLVM's parser

I would say that it does some extra work for you, which is not required by the standard, which would be to assume A::a() is static.

Bingo
  • 3,785
  • 6
  • 23
  • 27
  • Can someone answer me, does that mean for `static` functions, the `static` definition forms part of the name mangling, for resolution purposes? – Bingo Feb 25 '12 at 23:20
  • I don't know. But name-mangling is a linker problem, not a compiler problem. – Oliver Charlesworth Feb 25 '12 at 23:21
  • Any insight on why Apple's LLVM compiles it fine? Does that mean LLVM's parser does name resolution in some other order? – fang Feb 25 '12 at 23:21
  • @fang What compiler are you using? – Bingo Feb 25 '12 at 23:27
  • @Bingo i686-apple-darwin11-llvm-g++-4.2 is the one that complains about ambiguity. I tried g++-mp-4.7 and it's the same error. – fang Feb 25 '12 at 23:28
  • @fang see my edit. The compiler can't see from the parameters which one, because you could mean the case of default `int c = 0`. – Bingo Feb 25 '12 at 23:33
  • Yes I see your point. I guess that must be the reason. However I'm still unhappy with gcc on this because LLVM compiler was somehow able to understand what I want to do. After writing tons of code in Xcode and suddenly decide to try a build with gcc, it's frustrating to see compile errors like this, especially when I've been carefully trying to avoid tricky designs that might be compiler specific. – fang Feb 25 '12 at 23:38
  • @fang no problems :) I understand your frustration too. These things can be hard to debug, and I can see why you want this feature! – Bingo Feb 25 '12 at 23:40