哪些转换应该含糊不清?

时间:2017-08-11 13:29:24

标签: c++ language-lawyer overload-resolution conversion-operator copy-initialization

我有一些代码如下:

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都没有给出错误。谁没错?

1 个答案:

答案 0 :(得分:2)

TL;博士

歧义。 (另外,如果你停在tl; dr,那么language-lawyer标签可能不是你的茶杯。^ _ ^)

扰流

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

将其与current C++ working draft

分开

初始值设定项[dcl.init]

在这两种情况下

按用户定义的转换[over.match.copy]

复制类的初始化

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

  • 转换T的构造函数是候选者([over.match.copy]/1.1
    • bar::bar(const foo& foo);是候选人
  • 初始化程序表达式的类型为_cv_ S,因此会考虑非显式conversion functions :( [over.match.copy]/1.2
    • foo::operator bar() const未隐藏在foo内或const foo内,并产生与bar相同的T,因此是候选人。< / LI>

所以我们的候选人名单在两种情况下都是相同的:

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

在这两种情况下,我们都有user-defined conversion组成的:

  1. 源类型标准转换为用户定义的转换参数
  2. 用户定义的转换(上述两个函数之一)到结果类型
  3. 将结果类型标准转换为目标类型
  4. 如果我们选择构造函数,“结果类型”是“结构对象由构造函数初始化的目标类型的cv非限定版本的prvalue”([dcl.init]/17.6.3),因此对于两个候选函数,第二个标准转换是身份bar - &gt; bar)。

    重载决议[over.match]

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

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

    bar::bar(const foo& foo)

    foo::operator bar() const

    选择最佳可行功能[over.best.ics]

    两者都是 Identity =&gt;用户定义的转换=&gt;身份,即user-defined conversion sequences

    排名转换序列over.ics.rank

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

    • (X)不是列表初始化序列([over.ics.rank]/3
    • (X)不是标准转换序列([over.ics.rank]/3.2
    • (X)这两个序列不包含“相同的用户定义的转换函数或构造函数,或者在聚合初始化中初始化相同的类”([over.ics.rank]/3.3

    转换序列难以区分,即既不好也不差

    最佳可行功能over.match.best

    这两种功能都是“更好”的功能吗?仅在one of the following applies

    两者都不是“更好”的功能,因此呼叫形式不正确[over.match.best]/2