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 有时允许您将临时对象绑定到非常量左值引用。
这是对正在发生的事情的细分:
Test.get()
returns Test
对象的副本。它是临时的,因为你直接将它传递给 Process()
(简而言之,如果它没有名称,它就是临时的)。
- 现在开始第一个重载决议。
Process(MyChar&)
将是最接近类型的匹配,但它不合适,因为只有 const 左值引用可以绑定到一个临时的。但是 MyChar
隐式转换为 char,因此下一个最佳重载是 Process(char)
,它被选中。
- 第二个
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);
对于任何失礼表示歉意,这是我第一次 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 有时允许您将临时对象绑定到非常量左值引用。
这是对正在发生的事情的细分:
Test.get()
returnsTest
对象的副本。它是临时的,因为你直接将它传递给Process()
(简而言之,如果它没有名称,它就是临时的)。- 现在开始第一个重载决议。
Process(MyChar&)
将是最接近类型的匹配,但它不合适,因为只有 const 左值引用可以绑定到一个临时的。但是MyChar
隐式转换为 char,因此下一个最佳重载是Process(char)
,它被选中。 - 第二个
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);