通过初始标准转换序列区分用户定义的转换序列



该标准似乎提供了两条规则来区分涉及用户定义的转换运算符的隐式转换序列:

C++11

13.3.3 最佳可行函数

[...] 一个可行的函数 F1 被定义为比另一个可行的函数更好的函数 F2 如果 [...]

  • 上下文是通过用户定义的转换(请参阅 8.5、13.3.1.5 和 13.3.1.6(和 从返回类型 F1 到目标类型的标准转换序列(即 正在初始化的实体(是比标准转换序列更好的转换序列 将 F2 的类型返回到目标类型。

13.3.3.2 对隐式转换序列进行排名 [over.ics.rank]

3 - 同一形式的两个隐式转换序列是不可区分的转换序列,除非其中一个 以下规则适用:[...]

    如果用户定义的转换
  • 序列 U1 包含相同的用户定义的转换函数或构造函数或聚合,则它们比另一个用户定义的转换序列 U2 更好 初始化和U1的第二标准转换序列优于第二标准 U2的转换顺序。
据我了解,13.3.3 允许编译器区分不同的

用户定义的转换运算符,而 13.3.3.2 允许编译器区分不同的函数(某些函数f的重载(,每个函数都需要在其参数中进行用户定义的转换(请参阅我的侧边栏给定以下代码(在 GCC 4.3 中(,为什么转换为引用调用两次?

是否有任何其他规则可以区分用户定义的转换序列?https://stackoverflow.com/a/1384044/567292 的答案表明 13.3.3.2:3 可以根据隐式对象参数(对转换运算符(的 cv 限定或对构造函数或聚合初始化的单个非默认参数的 cv 限定来区分用户定义的转换序列,但我看不出这有什么相关性,因为这需要在各个用户定义的转换序列的第一个标准转换序列之间进行比较, 标准似乎没有提到。

假设 S1 优于 S2,其中 S1 是 U1 的第一个标准转换序列,

S2 是 U2 的第一个标准转换序列,那么 U1 是否优于 U2?换句话说,此代码的格式是否正确?

struct A {
    operator int();
    operator char() const;
} a;
void foo(double);
int main() {
    foo(a);
}

g++(4.5.1(,Clang(3.0(和Comeau(4.3.10.1(接受它,更喜欢非常量限定的A::operator int(),但我希望它被拒绝,因为它模棱两可,因此格式不正确。 这是标准的不足还是我对它的理解的缺陷?

这里的诀窍是,从类类型转换为非类类型实际上不会将任何用户定义的转换作为隐式转换序列进行排名。

struct A {
    operator int();
    operator char() const;
} a;
void foo(double);
int main() {
    foo(a);
}

在表达式foo(a)中,foo显然命名了一个非重载的非成员函数。 该调用需要使用单个表达式 adouble 类型的函数参数进行复制初始化 (8.5p14(,它是类类型 A 的左值。

由于目标类型double不是符合 cv 条件的类类型,而是源类型A,因此候选函数由第 13.3.1.5 节定义,带有 S=AT=double 。 仅考虑类 A 中的转换函数和A的任何基类。 在以下情况下,转换函数在候选项集中:

  • 它没有隐藏在类A中,并且
  • 它不是explicit(因为上下文是复制初始化(,并且
  • 标准转换序列可以将函数的返回类型(不包括任何引用限定符(转换为目标类型double

好的,两个转换函数都符合条件,因此候选函数是

A::operator int();        // F1
A::operator char() const; // F2

使用 13.3.1p4 中的规则,每个函数都将隐式对象参数作为其参数列表中的唯一内容。 F1的参数列表是"(左值引用A(",F2的参数列表是"(左值引用const A("。

接下来,我们检查函数是否可行(13.3.2(。 每个函数的参数列表中都有一个类型,并且有一个参数。 每个参数/参数对是否有隐式转换序列? 确定:

  • ICS1(F1):将隐式对象参数(类型左值引用A(绑定到表达式a(类型为A的左值(。
  • ICS1(F2):将隐式对象参数(类型左值引用const A(绑定到表达式a(类型为A的左值(。

由于没有派生到基的转换,因此这些引用绑定被视为标识转换的特殊情况 (13.3.3.1.4p1(。 是的,这两个功能都是可行的。

现在我们必须确定一个隐式转换序列是否比另一个更好。 这属于 13.3.3.2p3 中大列表中的第五个子项:两者都是同一类型的引用绑定,除了顶级 cv 限定符。 由于 ICS1(F2) 的引用类型比 ICS1(F1) 的引用类型更符合 cv 条件,因此ICS1(F1)ICS1(F2) 更好。

因此F1A::operator int()是最可行的函数。 甚至没有比较用户定义的转换(严格定义由SCS +(转换构造函数或转换函数(+ SCS组成的ICS(。

现在,如果foo重载,则需要比较参数a的用户定义转换。 因此,用户定义的转换(标识 + A::operator int() + intdouble (将与其他隐式转换序列进行比较。

最新更新