Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the Compiler does not detect correct function signature in error?

Tags:

c++

function

gcc

The question is in reference to this, which was posted a little while earlier.
While the OP was happy accepting the answer which solved his problem I was a little intrigued with a detail as to why compiler gave a seemingly wrong error.

Below is a small code sample I created to demonstrate the same:

    class YourClass
    {
    };

    class YourClass2
    {
    };
    class MyClass
    {
        public:
            void doSomething(YourClass2 obj)
            {
                //Nothing more Interesting to do
            }

    };

    int main()
    {
        YourClass *ptr = new YourClass();
        MyClass obj;
        obj.doSomething(ptr);

        return 0;
    }

Compiling this with GCC(4.3.4) gives a seemingly strange error result:

prog.cpp: In function ‘int main()’:
prog.cpp:23: error: no matching function for call to ‘MyClass::doSomething(YourClass*&)’
prog.cpp:13: note: candidates are: void MyClass::doSomething(YourClass2)

So the Question is:
Why does the compiler treat the call,

obj.doSomething(ptr);

as call to a function with prototype,

MyClass::doSomething(YourClass*&)

and not

MyClass::doSomething(YourClass*)

which seems to be the obvious case.

like image 931
Alok Save Avatar asked Aug 18 '11 17:08

Alok Save


3 Answers

First, note that the expression ptr (not the variable ptr) has type YourClass *&. This is important; it's the only way reference types can work (otherwise you'd be making a reference to a copy when you do YourClass *&x = ptr, and it's also why YourClass *&x = (ptr + 1) fails). As such, the compiler starts its search for a function with MyClass::doSomething(YourClass *&).

Of course, this call can match a prototype MyClass::doSomething(YourClass *). It can also match MyClass::doSomething(const YourClass *) or many others. There's potentially dozens (or, with multiple parameters, easily hundreds or thousands) of prototypes that could potentially match this call; however, none could be found.

So the compiler gives up, and gives an error. In the error, rather listing every theoretically possible match, it cites the one prototype that most closely matches what it was originally looking for; that is, MyClass::doSomething(YourClass *&).

like image 143
bdonlan Avatar answered Oct 26 '22 23:10

bdonlan


As others have stated, the compiler is trying to be helpful, and probably confusing you. Lets start with the simplest error:

error: no matching function for call to obj.doSomething(ptr)

While the error message is correct, the information that it provides is very limited. In this example the code is simple to follow, but consider a more complex piece of code. You read the error message and you may think... what's obj?, what's ptr? So it tries to help you and tells you what obj is:

error: no matching function for call to ‘MyClass::doSomething(ptr)’

Well, that's better, it is telling you at least in what class you need to look for the overload, but consider that the class was std::ostream and the function operator<<... there are just too many overloads, and still, what is the type of ptr? So it moves forward and tries to describe the argument: The argument is an lvalue of type YourClass*... and I have seen that type of error message produced in the past:

error: no matching function for call to ‘MyClass::doSomething’ that takes an YourClass* lvalue as argument.

Ok, so the error report is complete. Now think that the function might have more arguments, and the error message can turn into a complex beast (imagine a list of 5 "rvalue of type XXX and an lvalue of type YYY and ..."). The next thing is making the syntax of the error message just as precise (the lvalue-ness of the argument is important, or the rvalue-ness would be important, so that piece of information has to be present). So it rewrites the error message again:

error: no matching function for call to ‘MyClass::doSomething(YourClass*&)’

The problem is that you are trying to interpret that as a function signature, but it is rather the description of the function call.

Error messages are not defined in the standard, and they differ from one compiler to another, even from one version to another within the same compiler. At the end of the day you need to learn to read the error messages and what they mean.

like image 27
David Rodríguez - dribeas Avatar answered Oct 26 '22 23:10

David Rodríguez - dribeas


The compiler is trying to be helpful.

MyClass::doSomething(YourClass*&)

This does not name any function: there is no function in your code that matches this.

YourClass*& is the type of the argument you are trying to pass to a function named MyClass::doSomething: the argument (ptr) is an lvalue, represented in the error by the &.

The compiler needs some way to distinguish lvalue arguments from rvalue arguments in order to provide you with as much useful diagnostic information as possible; this is one succinct way to do this.

like image 36
James McNellis Avatar answered Oct 26 '22 21:10

James McNellis