为什么下面的代码是错误的(关于重载决议)

时间:2013-08-28 13:46:17

标签: c++ overloading

在gcc-4.8.1中给出以下代码

struct Base
{
};

struct Derive : private Base
{
};

void fn(Base, int);

struct Conv
{
    operator Base() const;
    operator Derive();
};

int main()
{
    Conv c;
    fn(c, 0);
    return 0;
}

当我给出上面的代码时,我收到了一个错误。我认为编译器会选择Conv::operator Base()但实际上编译器选择Conv::operator Derive()

但是当我提供以下代码时,编译器选择了Conv::operator Base()

struct Base
{
};

struct Derive// : private Base
{
};

void fn(Base, int);

struct Conv
{
    operator Base() const;
    operator Derive();
};

int main()
{
    Conv c;
    fn(c, 0);
    return 0;
}

2 个答案:

答案 0 :(得分:4)

您的c对象是非常量的,因此在第一种情况下,Derive重载是一个精确的常量匹配,仍然可以隐式转换为Base。在第二个示例中,Derive无法转换为Base,因此必须选择直接Base转化。

答案 1 :(得分:2)

关键是在选择转换序列之前不会检查访问说明符,因此代码感觉如:

struct base {};
struct derived : base {};
struct conv { 
   operator base() const;
   operator derived();
};
void fn(base);
int main() {
   conv c;
   fn(c);
}

此时有不同的有效转换序列:

  • 添加const资格,然后用户转换为基础
  • 用户转换为派生,派生到基本转化

第二次转换是一个更好的转换序列,它被选中。

这在13.3.3.1/2标准中处理:

  

隐式转换序列仅涉及参数的类型,cv限定和值类别以及如何转换它们以匹配参数的相应属性。其他属性(例如参数的生存期,存储类,对齐方式或可访问性以及参数是否为位字段)将被忽略。因此,虽然可以为给定的参数 - 参数对定义隐式转换序列,但在最终分析中,从参数到参数的转换可能仍然是不正确的。