0

给定 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;
}
4

2 回答 2

4

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

于 2013-08-28T13:48:27.593 回答
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 限定和值类别,以及如何转换这些以匹配参数的相应属性。其他属性,例如参数的生命周期、存储类、对齐方式或可访问性,以及参数是否为位域,都将被忽略。因此,尽管可以为给定的参数-参数对定义隐式转换序列,但从参数到参数的转换在最终分析中可能仍然是错误的

于 2013-08-28T13:58:02.553 回答