为什么编译器没有检测到错误的正确函数签名?

时间:2011-08-18 17:52:24

标签: c++ function gcc

问题是参考 this ,这是在不久前发布的。
尽管OP很乐意接受解决了他的问题的答案,但我对于为什么编译器给出了看似错误的错误的细节感到有点兴趣。

下面是我创建的一个小代码示例,用于演示相同的内容:

    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;
    }

使用 GCC(4.3.4)编译 this 会产生一个看似奇怪的错误结果:

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)

所以问题是:
为什么编译器会处理呼叫,

obj.doSomething(ptr);

调用带有原型的函数,

MyClass::doSomething(YourClass*&)

而不是

MyClass::doSomething(YourClass*)

这似乎是一个明显的例子。

4 个答案:

答案 0 :(得分:6)

首先,请注意表达式 ptr(不是变量 ptr)的类型为YourClass *&。这个很重要;它是引用类型可以工作的唯一方式(否则,当您执行YourClass *&x = ptr时,您将引用副本,这也是YourClass *&x = (ptr + 1)失败的原因)。因此,编译器开始搜索具有MyClass::doSomething(YourClass *&)的函数。

当然,此调用可以匹配原型MyClass::doSomething(YourClass *)。它也可以匹配MyClass::doSomething(const YourClass *)或许多其他人。可能存在数十个(或者,具有多个参数,容易数百或数千个)可能与此调用匹配的原型;然而,没有人能找到。

因此编译器放弃了,并给出了错误。在错误中,而不是列出每个理论上可能的匹配,它引用了一个最接近它最初寻找的原型;也就是MyClass::doSomething(YourClass *&)

答案 1 :(得分:4)

正如其他人所说,编译器正试图提供帮助,并且可能让您感到困惑。让我们从最简单的错误开始:

  

错误:没有匹配函数来调用obj.doSomething(ptr)

虽然错误消息是正确的,但它提供的信息非常有限。在这个例子中,代码很容易遵循,但考虑更复杂的代码。你阅读了错误信息,你可能会想...... 什么是obj?,什么是ptr?所以它试图帮助你并告诉你obj是什么:

  

错误:没有匹配函数来调用'MyClass :: doSomething(ptr)'

嗯,那更好,它告诉你至少在你需要查找重载的类中,但是考虑到类是std::ostream而函数operator<< ...只是过多的重载,仍然是ptr的类型是什么?所以它向前移动并试图描述参数:参数是类型为YourClass*左值 ...我已经看到过去产生的那种错误信息:

  

错误:没有匹配函数来调用'MyClass :: doSomething',它将YourClass*左值作为参数。

好的,所以错误报告已经完成。现在认为该函数可能有更多的参数,并且错误消息可以变成一个复杂的野兽(想象一下5的类型XXX的左值列表和一个类型为YYY的左值和......“)。接下来的事情是使错误消息的语法同样精确(参数的左值 - 的重要性,或 rvalue - 的重要性,因此必须存在一条信息)。所以它再次重写错误消息:

  

错误:没有匹配函数来调用'MyClass :: doSomething(YourClass *&amp;)'

问题是你试图将其解释为函数签名,但它更像是函数调用的描述。

错误消息未在标准中定义,并且它们在一个编译器与另一个编译器之间存在差异,即使在同一编译器中也是从一个版本到另一个版本。在一天结束时,您需要学习阅读错误消息及其含义。

答案 2 :(得分:1)

编译器正试图提供帮助。

MyClass::doSomething(YourClass*&)

这并没有命名任何函数:代码中没有与此匹配的函数。

YourClass*&是您尝试传递给名为MyClass::doSomething的函数的参数的类型:参数(ptr)是左值,由{{在错误中表示1}}。

编译器需要某种方法来区分左值参数和右值参数,以便为您提供尽可能多的有用诊断信息;这是一种简洁的方法。

答案 3 :(得分:0)

编译器不需要生成对您有意义的消息。它需要告诉您代码中存在错误。现在它打印的消息是由编译器决定的。标准没有说明它应该打印什么消息,什么不打印。当编译器输出错误消息时,我认为该错误消息可能是好的/有用的,也可能是坏的/无用的,但不是“错误的”。