【问题标题】:Precedence in choosing conversion functions for assign initialization为赋值初始化选择转换函数的优先级
【发布时间】:2018-03-16 17:28:05
【问题描述】:

考虑以下代码sn-p:

class A;

class B { 
      public: 
         B(){} 

         B(A&) // conversion constructor that takes cv-unqualified A
         { 
              cout << "called B's conversion constructor" << endl; 
         } 
};

class A { 
      public: 
         operator B() const // conversion operator that takes cv-qualified A
         { 
              cout << "called A's conversion operator" << endl; 
              return B(); 
         } 
};

int main()
{
    B b = A(); // who gets called here?
    return 0;
}

根据this question,具有最少cv限定形式的转换序列获胜(规范中的13.3.3.2/3):

标准转换序列 S1 是更好的转换序列 标准转换序列 S2 如果 [...] S1 和 S2 是参考 绑定(8.5.3),引用所指的类型是 相同的类型,除了顶级 cv 限定符和类型 由 S2 初始化的引用比 cv 更合格 S1 初始化的引用所引用的类型

然而,在上面的 sn-p 中,转换运算符总是被选中,无论 A 在两个函数中是否是 cv 限定的。唯一的例外是,当构造函数和运算符都是 cv 限定时,编译器会抱怨在选择转换顺序时存在歧义,而 cv 不限定的情况则不会(为什么?)。

所以问题是:

  1. 为什么在这种情况下总是选择转换运算符?
  2. 为什么两个 cv-qualified 都会导致歧义,而 cv-unqualified 不会?

【问题讨论】:

  • 最多只能调用一次用户定义的隐式转换。

标签: c++ type-conversion qualifiers


【解决方案1】:

为了解决重载问题,A::operator B() 有一个隐式对象参数,其类型为cv A&amp;。这个参数的特殊之处在于它可以绑定到一个右值,即使它是根据[over.match.funcs]/5的非常量类型的左值引用:

在重载决议期间,隐含的对象参数与​​其他参数没有区别。但是,隐式对象参数保留其身份,因为不能应用用户定义的转换来实现与它的类型匹配。对于没有 ref-qualifier 声明的非静态成员函数,适用附加规则:

  • 即使隐式对象参数不是 const 限定的,也可以将右值绑定到参数,只要在所有其他方面参数可以转换为隐式对象参数的类型。 [ 注意:这样的参数是右值这一事实不会影响隐式转换序列的排名。 — 尾注 ]

[over.ics.ref]/3

除了隐式对象参数(参见 [over.match.funcs]),如果需要将非易失性 const 类型的引用以外的左值引用绑定到右值或将右值引用绑定到函数左值以外的左值。 [ 注意:这意味着,例如,如果候选函数具有非 const 左值引用参数(隐式对象参数除外)并且相应的参数需要创建一个临时参数来初始化左值引用(参见 [dcl.init.ref])。 — 尾注 ]

所以如果转换构造函数带有一个非常量参数,它是不可行的,而转换运算符总是可行的,这使得重载决议总是选择转换运算符。


如果转换构造函数采用 const 参数且转换运算符为非 const,则根据[over.ics.ref]/1,两种隐式转换都是身份转换:

当引用类型的参数直接绑定到参数表达式时,隐式转换序列是恒等转换...

然后根据[over.ics.rank]/3

标准转换序列S1是比标准转换序列S2更好的转换序列如果

  • ...

  • S1 和 S2 是引用绑定,并且引用所引用的类型除了顶级的 cv-qualifiers 之外是相同的类型,并且 S2 初始化的引用所引用的类型比类型更 cv-qualified由 S1 初始化的引用所指向的引用。

因此选择了非常量版本(转换运算符)。


最后,如果两者都是const,它们之间没有区别,也没有特殊规则适用,所以重载解析会因为歧义而失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多