【问题标题】:Incorrect overload resolution with value of const argument as 0const 参数值为 0 的重载决议不正确
【发布时间】:2016-10-10 00:59:59
【问题描述】:

我有一个类B 有两个重载函数int Set(B *);int Set(const A&);。类A 需要一个构造函数参数unsigned char。当Set 使用const unsigned char 调用时,其值为0,它被解析为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.2c++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

【问题讨论】:

  • Unable to reproduce 在 GCC 4.9.2 中
  • @CoryKramer:在 c++98 中可以重现。
  • 嗯,很奇怪。想知道是否仅仅是因为在某处本质上存在#DEFINE NULL 0,因为它在nullptr之前,所以它认为0应该作为指针传递(因为它认为你正在传递NULL。这个问题提到了@987654323 @ 和 here.
  • 添加了 C++98 标签,因为它只显示在该版本中。我无法测试 C++03 来确认它的添加。
  • @NathanOliver:另外,在 C++03 中复制。

标签: c++ constants overloading c++98


【解决方案1】:

标准之间的区别在这里:

C++98 [conv.ptr]

空指针常量是整数类型的整数常量表达式右值,其计算结果为零。

C++11 [conv.ptr]

空指针常量是一个整数文字,其值为 0 或 std::nullptr_t 类型的纯右值。

const unsigned char a = 0; 满足 C++98 对整型常量表达式的定义。当然a 不是右值,但似乎左值到右值的转换适用并且仍然比用户定义的从unsigned charA 的转换更好的匹配。

a 不是文字,这就是 C++11 中行为不同的原因。

【讨论】:

  • 很好的答案,比我的要好。
  • 作为确认,您的答案很成功。将(unsigned char)0 传递给Set 与C++11、C++14 的行为相同。
【解决方案2】:

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 在您的帖子下正确提到的那样,一旦使用 c++11 标准(将 -std=c++11 标志添加到编译器),此行为就会消失。

【讨论】:

  • 但是为什么 0 被视为空指针呢?任何设置为 0 的 const 值都可能具有这种未定义的行为。看起来很危险。
  • CoryKramer 给你答案。 NULL 被定义为 0,所以不知何故 0 在它的类型上是模棱两可的。
  • DR456 中有关于此行为的讨论。我没有发现任何在 C++11 中改变这种行为的后续行动
  • @Revolver_Ocelot:解释得很好。
猜你喜欢
  • 1970-01-01
  • 2011-01-08
  • 2010-12-15
  • 2014-11-11
  • 2020-04-07
  • 2017-05-09
  • 2017-11-20
  • 2015-03-29
  • 2019-06-12
相关资源
最近更新 更多