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

Alo*_*ave 7 c++ gcc function

问题是参考这个,这是在不久前发布的.
尽管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;
    }
Run Code Online (Sandbox Code Playgroud)

编译海湾合作委员会(4.3.4)给出了一个看似奇怪的错误的结果:

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)
Run Code Online (Sandbox Code Playgroud)

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

obj.doSomething(ptr);
Run Code Online (Sandbox Code Playgroud)

作为对原型的函数的调用,

MyClass::doSomething(YourClass*&)
Run Code Online (Sandbox Code Playgroud)

并不是

MyClass::doSomething(YourClass*)
Run Code Online (Sandbox Code Playgroud)

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

bdo*_*lan 6

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

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

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

  • @Als,被调用的函数没有签名`(YourClass*)`.你传入了对指针的引用(即_expression_`ptr`的类型为`YourClass*&`).如果它能找到的只是一个原始指针`(YourClass*)`,它会将该指针引用转换为指针并传递它. (2认同)

Dav*_*eas 4

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

\n\n
\n

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

\n
\n\n

虽然错误消息是正确的,但它提供的信息非常有限。在此示例中,代码很容易理解,但请考虑一段更复杂的代码。您阅读错误消息后可能会想...什么是 obj?,什么是 ptr?所以它试图帮助你并告诉你什么obj是:

\n\n
\n

错误:没有匹配的函数可调用 \xe2\x80\x98MyClass::doSomething(ptr)\xe2\x80\x99

\n
\n\n

好吧,这样更好,它至少告诉您需要在哪个类中查找重载,但是考虑一下该类std::ostream和该函数operator<<......重载太多了,而且仍然是什么类型ptr?因此它继续前进并尝试描述该参数:该参数是类型的左值YourClass*...并且我已经看到过去产生的这种类型的错误消息:

\n\n
\n

错误:没有匹配的函数可以调用 \xe2\x80\x98MyClass::doSomething\xe2\x80\x99 ,该函数以左YourClass*值作为参数。

\n
\n\n

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

\n\n
\n

错误:没有匹配的函数可调用 \xe2\x80\x98MyClass::doSomething(YourClass*&)\xe2\x80\x99

\n
\n\n

问题是您试图将其解释为函数签名,但它实际上是函数调用的描述。

\n\n

标准中没有定义错误消息,并且不同的编译器之间存在差异,甚至同一编译器中的一个版本之间也存在差异。最终,您需要学会阅读错误消息及其含义。

\n