const 参数值为 0 的重载决策不正确
Incorrect overload resolution with value of const argument as 0
我有一个 class B
有两个重载函数 int Set(B *);
和 int Set(const A&);
。 class A
需要构造函数参数 unsigned char
。当使用值为 0
的 const unsigned char
调用 Set
时,它被解析为 Set(B*)
而当传递的值不为零时,它解析为 Set(const A&)
(按照我的预期)。
重载解析在非 const unsigned char
上正常工作,但在 const unsigned char
上失败,值设置为 0
。为什么?
以下代码说明了使用 const 和非 const unsigned char
调用 Set
时的差异
#include <iostream>
using namespace std;
class A{
char m_byteValue;
public:
A(unsigned char c) {
m_byteValue = c;
}
};
class B{
int m_a;
public:
B(){
m_a = 2;
}
int Set(B *);
int Set(const A&);
};
int B::Set(const A& v) {
cout << "I am in the const ref function\n";
return 0;
}
int B::Set(B* p) {
cout << "I am in the pointer function\n";
return 0;
}
int main(){
const unsigned char a = 0;
const unsigned char b = 1;
unsigned char c = 0;
unsigned char d = 1;
B var;
var.Set(a);
var.Set(b);
var.Set(c);
var.Set(d);
return 0;
}
输出(由 gcc 4.9.2
c++98 编译):
Demo - 在 ideone c++ 5.1
I am in the pointer function // Why?
I am in the const ref function
I am in the const ref function
I am in the const ref function
Clang重现了错误,还好在编译时也给了你答案:
overloading_incorrect.cxx:41:13: warning: expression which evaluates
to zero treated as a null pointer constant of type 'B *'
[-Wnon-literal-null-conversion]
var.Set(a);
^
正如 NathanOliver 在您的 post 下正确提到的那样,一旦使用 c++11 标准(向编译器添加 -std=c++11
标志),此行为就会消失。
标准的区别在这里:
C++98 [conv.ptr]
A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero.
C++11 [conv.ptr]
A null pointer constant is an integer literal with value zero or a prvalue of type std::nullptr_t
.
const unsigned char a = 0;
满足整数常量表达式的 C++98 定义。当然 a
不是右值,但似乎左值到右值的转换适用并且仍然比用户定义的从 unsigned char
到 A
的转换更好。
a
不是文字,这就是 C++11 中行为不同的原因。
我有一个 class B
有两个重载函数 int Set(B *);
和 int Set(const A&);
。 class A
需要构造函数参数 unsigned char
。当使用值为 0
的 const unsigned char
调用 Set
时,它被解析为 Set(B*)
而当传递的值不为零时,它解析为 Set(const A&)
(按照我的预期)。
重载解析在非 const unsigned char
上正常工作,但在 const unsigned char
上失败,值设置为 0
。为什么?
以下代码说明了使用 const 和非 const unsigned char
Set
时的差异
#include <iostream>
using namespace std;
class A{
char m_byteValue;
public:
A(unsigned char c) {
m_byteValue = c;
}
};
class B{
int m_a;
public:
B(){
m_a = 2;
}
int Set(B *);
int Set(const A&);
};
int B::Set(const A& v) {
cout << "I am in the const ref function\n";
return 0;
}
int B::Set(B* p) {
cout << "I am in the pointer function\n";
return 0;
}
int main(){
const unsigned char a = 0;
const unsigned char b = 1;
unsigned char c = 0;
unsigned char d = 1;
B var;
var.Set(a);
var.Set(b);
var.Set(c);
var.Set(d);
return 0;
}
输出(由 gcc 4.9.2
c++98 编译):
Demo - 在 ideone c++ 5.1
I am in the pointer function // Why?
I am in the const ref function
I am in the const ref function
I am in the const ref function
Clang重现了错误,还好在编译时也给了你答案:
overloading_incorrect.cxx:41:13: warning: expression which evaluates
to zero treated as a null pointer constant of type 'B *'
[-Wnon-literal-null-conversion]
var.Set(a);
^
正如 NathanOliver 在您的 post 下正确提到的那样,一旦使用 c++11 标准(向编译器添加 -std=c++11
标志),此行为就会消失。
标准的区别在这里:
C++98 [conv.ptr]
A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero.
C++11 [conv.ptr]
A null pointer constant is an integer literal with value zero or a prvalue of type
std::nullptr_t
.
const unsigned char a = 0;
满足整数常量表达式的 C++98 定义。当然 a
不是右值,但似乎左值到右值的转换适用并且仍然比用户定义的从 unsigned char
到 A
的转换更好。
a
不是文字,这就是 C++11 中行为不同的原因。