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!
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.
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.
Related
While reading about *this, I saw:
When a nonstatic member function is called for an object, the compiler
passes the object's address to the function as a hidden argument.
Then I tried:
#include <iostream>
class MyClass
{
int myVar;
public:
MyClass(const int& val) : myVar{val} {}
// int getVar(MyClass* this) <-- Error: expected ',' or '...' before 'this'
int getVar()
{
return this->myVar;
}
};
int main()
{
MyClass obj(22);
// std::cout << obj.getVar(&obj); <-- Error: no matching function
// std::cout << MyClass::getVar(&obj); <-- Error: no matching function
std::cout << obj.getVar();
return 0;
}
Why am I not able to access the hidden argument? Is it called 'hidden' because of that?
Are only compilers allowed to do this? Can't we explicitly mention *this in the function signature?
The closest answer I've found before asking this is this. But I tried that way and still got the error. Could I get an explanation of those error messages? Because, if the compiler actually modifies those function signatures to contain *this then that should have worked, isn't it?
Are only compilers allowed to do this?
Precisely. That's why it's called hidden: It's something that the compiler does on your behalf, but which is hidden from the C++ code that uses it.
The compiler must pass the this pointer to the member function somehow, but it does not need to tell you how it does it. It could compile the code to the equivalent of MyClass::getVar(&obj), passing the this pointer in the same way that it would pass the argument for the C function free(foo). Or it might use a different mechanism that is totally incompatible with non-member argument passing. What it does under the hood is defined by the platform's Abstract Binary Interface standard (ABI), which is not part of the C++ language standard. What happens under Windows could be vastly different from what happens under Linux, and Linux on ARM could be different from Linux on X86, etc.
That said, you can take a look at what actually happens by telling your compiler to produce the assembly code. For gcc, the incantation would be
g++ -S -Os interestingCode.cpp
This will produce a .s file that contains how g++ actually translated your code.
obj.getVar(&obj)
This version cannot compile because the getVar() member function is not declared to take any parameters.
MyClass::getVar(&obj)
This version is using the syntax to access a static function but getVar() is not static, nor does it accept any parameters.
Note: The obj.getVar() call works because it is specifying which object instance to use (i.e., the obj. part) to execute the member function and is conceptually how the member function is passed the this pointer.
When you are doing obj.getVar() it is already explicitly specified the pointer *this=&obj and passed implicitly to getVar. It is not hidden. It is explicitly passed leftside of the function. You can use obj.getVar() or ptrObj->getVar() but in C++ is not allowed to use such construction getVar(thisptr). Hidden means the variable named this is nowhere declared, but you can use inside the function.
As an interesting follow-up (not of big practical importance though) to my previous question:
Why does C++ allow us to surround the variable name in parentheses when declaring a variable?
I found out that combining the declaration in parentheses with injected class name feature may lead to surprising results regarding compiler behavior.
Take a look at the following program:
#include <iostream>
struct B
{
};
struct C
{
C (){ std::cout << "C" << '\n'; }
C (B *) { std::cout << "C (B *)" << '\n';}
};
B *y = nullptr;
int main()
{
C::C (y);
}
Compiling with g++ 4.9.2 gives me the following compilation error:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
It compiles successfully with MSVC2013/2015 and prints C (B *)
It compiles successfully with clang 3.5 and prints C
So obligatory question is which one is right? :)
(I strongly swayed towards clang version though and msvc way to stop declaring variable after just changing type with technically its typedef seems kind of weird)
GCC is correct, at least according to C++11 lookup rules. 3.4.3.1 [class.qual]/2 specifies that, if the nested name specifier is the same as the class name, it refers to the constructor not the injected class name. It gives examples:
B::A ba; // object of type A
A::A a; // error, A::A is not a type name
struct A::A a2; // object of type A
It looks like MSVC misinterprets it as function-style cast expression creating a temporary C with y as a constructor parameter; and Clang misinterprets it as a declaration of a variable called y of type C.
G++ is correct as it gives an error. Because the constructor could not be called directly in such a format without new operator. And although your code calls C::C, it looks like an constructor call. However, according to the C++11 standard 3.4.3.1, this is not a legal function call, or a type name (see Mike Seymour's answer).
Clang is wrong since it even does not call the correct function.
MSVC is something reasonable, but still it does not follow the standard.
Based on this
Incidentally, you can do this kind of assignment of a pointer to a
function as long as the target’s exception specification is no more
restrictive than the source’s
class A{};
class B{};
class C{};
void f() throw(A,B,C) {}
void (*pf)() throw(A,B);
int main()
{
pf = f; // pf is more restrictive than that of f. I expect an error here!
}
The last statement should not pass the compiler. However, I have tried VS2010 and GCC latest version. Neither or them complain about it.
Question> Why?
This looks like a bug in GCC and VS2010. Clang won't compile it, and it should not compile according to [except.spec]/5:
... A similar restriction applies to assignment to and initialization of pointers to functions, pointers to member functions, and references to functions: the target entity shall allow at least the exceptions allowed by the source value in the assignment or initialization.
The standard also includes the following example:
class A { /*...*/ };
void (*pf1)(); // no exception specification
void (*pf2)() throw(A);
void f() {
pf1 = pf2; // OK: pf1 is less restrictive
pf2 = pf1; // error: pf2 is more restrictive
}
It's a long-standing bug in g++: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12255
The underlying issue is that G++ just ignores exception-specifications on
non-function declarations. I think this choice originated in the uncertainty
about whether or not the exeception-specification would become part of a
function type rather than remain associated with the declaration.
It wouldn't surprise me if VS was similar in this regard.
Can you tell me why the following code is giving me the following error - call of overloaded "C(int)" is ambiguous
I would think that since C(char x) is private, only the C(float) ctor is visible from outside and that should be called by converting int to float.
But that's not the case.
class C
{
C(char x)
{
}
public:
C(float t)
{
}
};
int main()
{
C p(0);
}
This is discussed in "Effective C++" by Scott Meyer. The reason this is ambiguous is that they wanted to ensure that merely changing the visibility of a member wouldn't change the meaning of already-existing code elsewhere.
Otherwise, suppose your C class was in a header somewhere. If you had a private C(int) member, the code you present would call C(float). If, for some reason, the C(int) member was made public, the old code would suddenly call that member, even though neither the old code, nor the function it called had changed.
EDIT: More reasons:
Even worse, suppose you had the following 2 functions:
C A::foo()
{
return C(1.0);
}
C B::bar()
{
return C(1.0);
}
These two functions could call different functions depending on whether either foo or bar was declared as a friend of C, or whether A or B inherits from it. Having identical code call different functions is scary.
(That's probably not as well put as Scott Meyer's discussion, but that's the idea.)
0 is an int type. Because it can be implicitly cast to either a float or char equally, the call is ambiguous. Visibility is irrelevant for these purposes.
Either put 0.0, 0., or 0.0f, or get rid of the C(char) constructor entirely.
Edit: Relevant portion of the standard, section 13.3:
3) [...] But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
First, a subset of the candidate functions—those that have the proper number of arguments and meet certain other conditions—is selected to form a set of viable functions (13.3.2).
Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
4) If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (clause 11) in the context in which it is used, the program is ill-formed.
Note that visibility is not part of the selection process.
I don't think that:
C p(0);
is being converted to:
C(float t)
you probably need to do:
C p(0.0f);
Say I have three classes:
class X{};
class Y{};
class Both : public X, public Y {};
I mean to say I have two classes, and then a third class which extends both (multiple-inheritance).
Now say I have a function defined in another class:
void doIt(X *arg) { }
void doIt(Y *arg) { }
and I call this function with an instance of both:
doIt(new Both());
This causes a compile-time error, stating that the function call is ambiguous.
What are the cases, besides this one, where the C++ compiler decides the call is ambiguous and throws an error, if any? How does the compiler determine what these cases are?
Simple: if it's ambiguous, then the compiler gives you an error, forcing you to choose. In your snippet, you'll get a different error, because the type of new Both() is a pointer to Both, whereas both overloads of doIt() accept their parameters by value (i.e. they do not accept pointers). If you changed doIt() to take arguments of types X* and Y* respectively, the compiler would give you an error about the ambiguous function call.
If you want to explicitly call one or the other, you cast the arguments appropriately:
void doIt(X *arg) { }
void doIt(Y *arg) { }
Both *both = new Both;
doIt((X*)both); // calls doIt(X*)
doIt((Y*)both); // calls doIt(Y*)
delete both;
I get this error with gcc:
jeremy#jeremy-desktop:~/Desktop$ g++ -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18: error: call of overloaded ‘doIt(Both&)’ is ambiguous
test.cpp:7: note: candidates are: void doIt(X)
test.cpp:11: note: void doIt(Y)
This is a perfect example of using boost::implicit_cast:
void doIt(X *arg) { }
void doIt(Y *arg) { }
doIt(boost::implicit_cast<X*>(new Both));
Unlike with other solutions (including static_cast), the cast will fail if no implicit conversion from Both* to X* is possible. This is done by a trick, best shown at a simple example:
X * implicit_conversion(X *b) { return b; }
That's what is boost::implicit_cast, just that it is a template which tells it the type of b.
The compiler does a depth-search, not a breadth-search for picking overloads.
The full answer is in Herb Sutter's exceptional C++, unfortunately I don't have the book in hand.
Edit: Got the book at hand now
It's called the depth first rule is called "The Interface Principle":
The Interface Principle For a class X,
all functions, including free
functions, that both (a) "mention"
X, and (b) are "supplied with" X
are logically part of X, because they
form part of the interface of X.
but there is a secondary rule called the "Koenig Lookup", that makes things harder.
Quote:"(simplified): if you supply a
function argument of class type (here
x, of type A::X), then to look up the
correct function name the compiler
considers matching names in the
namespace (here A) containing the
argument's type" -Herb Sutter,
Exceptional C++, p120
you need to explicitly cast your argument to either x or y
doIt(new Both());
so add...
(X *) or (Y *)
like...
doIt((X *)new Both());
AFAIK the C++ compiler will always pick the closest and most specific match that it can determine at compile time.
However, if your object is derived from both, I think that the compiler should give you an error or at least a very severe warning. Declaration order should not matter since this is about subtyping relations, and the first object is not "more of a subtype" than the other.