C++ 重载解析查询

C++ Overload Resolution Query

对于任何失礼表示歉意,这是我第一次 post 到任何此类论坛。

下面的代码来自一些实验,当 运行 给出的输出让我感到惊讶时,即

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

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

这是对正在发生的事情的细分:

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

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

如果您根本不关心交叉编译器的兼容性,那么您一定不要依赖它。例如,对于 GCC 7.3,您的代码的无转换运算符版本将无法编译:

error: cannot bind non-const lvalue reference of type ‘MyChar&’ to an rvalue of type ‘MyChar’

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

Process(const MyChar&)

或不通过临时:

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