过载解析和用户定义的转换

Overload resolution and user defined conversion

考虑简单的代码:

struct A;
struct B {
  B(){}
  B(A const&){ }
};

struct A {
  operator int() const {return 0;};
};
void func(B){}
void func(char){}

int main()
{
func(A()); //ambiguous call oO
}

首先,我不确定我是否理解正确,所以请随时纠正我。

我的理解是应该选择 void func(B),因为 func 的参数是 A,它是 class 类型,因此需要的转换类型是 "User defined conversion sequence"

现在来自 IBM C++ 参考:

A user-defined conversion sequence consists of the following:

  • A standard conversion sequence
  • A user-defined conversion
  • A second standard conversion sequence

现在有两个用户定义的转换 B::B(const A&)A::operator int (const A&);

所以顺序是

-> A() -> B::B(const A&) -> Standard conversion (identity conversion)

-> A() -> A::operator int (const A&) -> Standard conversion (integral conversion)

因为整数转换比恒等转换更糟糕我认为 void func(B) 会调用但调用仍然是模棱两可的。

所以请帮我看看我哪里错了,为什么调用不明确。非常感谢:)

这里的两个转换序列,A -> BA -> int都是用户定义的,因为它们通过您定义的函数运行。

自定义转换序列排序规则见13.3.3.2(N3797):

User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function or constructor or they initialize the same class in an aggregate initialization and in either case the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2

这两个转换序列不包含相同的用户定义转换函数,并且它们在聚合初始化中不初始化相同的class(因为一个初始化int)。

所以一个序列排在另一个序列之上是不正确的,因此这段代码是不明确的。

so the sequence are -> A() -> B::B(const A&) -> Standard conversion (identity conversion)

没有!摘自标准(草案)[over.best.ics](强调我的):

  1. If no conversions are required to match an argument to a parameter type, the implicit conversion sequence is the standard conversion sequence consisting of the identity conversion (13.3.3.1.1).

func(A()) 不是标识,它是用户定义的。再次根据标准,[[conv]]:

For class types, user-defined conversions are considered as well; see 12.3. In general, an implicit conversion sequence (13.3.3.1) consists of a standard conversion sequence followed by a user-defined conversion followed by another standard conversion sequence.

我认为您对标准转换有误解。它们与用户定义的 types/classes 无关。标准转换仅适用于内置类型:左值到右值转换、数组到指针转换、函数到指针转换、整数提升、浮点提升、整数转换、浮点转换、浮点整数转换、指针转换、指向成员的指针转换、布尔值转换和限定转换。 A -> int 不是其中任何一个,而是用户定义的转换。用户定义的转换标准,[[class.conv]] 即 12.3:

Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

您有两个相同等级的用户定义转换序列(请参阅 M.M 的回答了解原因),因此编译器希望您消除歧义。