首页 > 解决方案 > C++ 重载解析查询

问题描述

为任何失礼道歉,这是我在任何此类论坛上的第一篇文章。

下面的代码是一些实验的结果,运行时的输出让我感到惊讶,即

Inside char ch
Inside MyChar ch

我的问题是为什么?更准确地说,为什么编译器会通过首先将 MyChar.get 返回的值转换为 char 然后调用来解决对 Process 的调用

void Process(char ch)

而不仅仅是打电话

void Process(MyChar &ch)

如果

MyChar.operator char() 

然后从 MyChar 的定义中删除

void Process(MyChar &ch)

像我预期的那样被调用。

我正在使用 MS Visual C++ 2008 进行编译。

这可能是一个众所周知的现象,但我的搜索尝试未能发现任何有用的信息。

非常感谢,史蒂夫。

class MyChar
{
public:
    MyChar(){m_ch=1;};
    MyChar(char ch){m_ch=ch;};
   ~MyChar(){};
    char m_ch;
    operator char(){return m_ch;};
    MyChar get(){return *this;};
};

void Process(MyChar &ch);
void Process(char ch);


int main()
{
    MyChar Test;
    Process(Test.get());
    return 0;
}

void Process(MyChar &ch)
{
    printf("\nInside MyChar ch");
}

void Process(char ch)
{
    printf("\nInside char ch");
    MyChar chch(ch);
    Process(chch);
}

标签: c++overload-resolution

解决方案


VS 2008 现在已经很老了,而且并不以其出色的标准合规性而闻名。一般来说,期待一些奇怪的行为。请参阅@IgorTandetnik 的评论:与 C++ 语言规则相反,VS 2008 有时允许您将临时对象绑定到非 const 左值引用。

以下是正在发生的事情的细分:

  1. Test.get()返回对象的副本Test。这是一个临时的,因为你直接将它传递给Process()(简而言之,如果它没有名称,它是一个临时的)。
  2. 现在第一个重载决议开始了。Process(MyChar&)将是关于类型的最接近的匹配,但它不合适,因为只有const左值引用可以绑定到临时。但是MyChar有一个到 char 的隐式转换,所以下一个最好的重载是Process(char), 被选中。
  3. 第二次Process()调用触发另一个重载决议。你用MyChar左值调用它chch。AMyChar&可以绑定到MyChar左值没问题。因为相同的类型Process(MyChar&)是最好的匹配并被选中。Process(char)也是一个候选,但因为它涉及类型转换,所以它是一个更糟糕的匹配。

到目前为止,一切都很好。VS 2008 的行为完全符合标准的预期和要求。现在,当您删除隐式转换时,VS 2008 的非标准行为开始生效。Process(char)不再是可以调用的有效函数,因此仅Process(MyChar&)保留为候选函数并被选中。

但是,如果您完全担心交叉编译器的兼容性,则不能依赖它。例如,对于 GCC 7.3,您的代码的 no-conversion-operator 版本将无法编译:

错误:无法将“MyChar&”类型的非常量左值引用绑定到“MyChar”类型的右值</p>

Clang 给出了类似的错误消息。实现所需行为的标准符合方法是将const添加到Process函数的签名中:

Process(const MyChar&)

或不通过临时:

MyChar Test;
MyChar AnotherChar = Test.get();
Process(AnotherChar);

推荐阅读