这些转换中的哪一个应该是不明确的?

Which of these conversions should be ambiguous?

我有如下代码:

class bar;

class foo
{
public:
    operator bar() const;
};

class bar
{
public:
    bar(const foo& foo);
};

void baz() {
    foo f;
    bar b = f;   // [1]

    const foo f2;
    bar b2 = f2; // [2]
}

GCC 在 [2] 而不是 [1] 处给出错误。 Clang 在两者上都给出了错误,显然 MSVC 在两者上都没有给出错误。谁说得对?

tl;博士

模棱两可。 (此外,如果您在 tl;dr 停留,那么 language-lawyer 标签可能不是您的菜。^_^)

剧透

两位候选人都有一个 const foo& 参数,它同样绑定到 const foofoo 参数。没有其他规则更喜欢一个或另一个功能。


将其分解为 current C++ working draft

初始化器[dcl.init]

在这两种情况下

通过用户定义的转换 class 的复制初始化 [over.match.copy]

T 是被初始化的类型,在这两种情况下都是 barS是初始化表达式的类型,在fooconst foo两种情况下分别是

  • T 的转换构造函数是候选者 ([over.match.copy]/1.1)
    • bar::bar(const foo& foo);是候选人
  • 初始化表达式的类型是 _cv_ S 所以不显式 conversion functions are considered: ([over.match.copy]/1.2)
    • foo::operator bar() const 未隐藏在 fooconst foo 内,并产生 barT 相同,因此是候选者.

所以我们的候选列表在这两种情况下是相同的:

  • bar::bar(const foo& foo)
  • foo::operator bar() const

在这两种情况下,我们都有一个 user-defined conversion 包括:

  1. 源类型到用户定义的转换参数的标准转换
  2. 用户自定义转换(以上两个函数之一)到结果类型
  3. 结果类型到目标类型的标准转换

如果我们select构造函数,"result type"是"a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor"([dcl.init]/17.6.3),所以对于两个候选函数,第二个标准转换是身份 (bar -> bar).

过载分辨率[over.match]

对可行的候选函数进行子集化[over.match.viable]

Per [dcl.init]/17.6.3,初始化表达式将成为 selected 调用的参数,分别在 fooconst foo 两种情况下。

bar::bar(const foo& foo)

foo::operator bar() const

Select最佳可行函数[over.best.ics]

两者都是Identity => User Defined Conversion => Identity,即user-defined conversion sequences.

排名转换序列over.ics.rank

我们可以建立序列之间的排名吗?仅当 one of the following applies

  • (X) 不是列表初始化序列 ([over.ics.rank]/3)
  • (X) 不是标准的转换序列([over.ics.rank]/3.2)
  • (X) 两个序列不包含"the same user-defined conversion function or constructor or [...] initialize the same class in an aggregate initialization" ([over.ics.rank]/3.3)

转换序列无法区分,即,既不是更好也不是更坏

最佳可行函数over.match.best

这两个函数都是 'better' 函数吗?仅当 one of the following applies

两者都不是 'better' 函数,因此 调用格式错误 [over.match.best]/2