哪些转换应该含糊不清?

Tav*_*nes 13 c++ conversion-operator language-lawyer overload-resolution 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]
}
Run Code Online (Sandbox Code Playgroud)

GCC在[2]处给出错误,但不是[1].Clang给出了两个错误,显然MSVC都没有给出错误.谁是对的?

TBB*_*Ble 2

太长了;博士

模糊的。(另外,如果您停在 tl;dr 处,那么该language-lawyer标签可能不适合您。^_^)

剧透

两个候选者都有一个const foo&参数,它同等地绑定到const fooorfoo参数。没有出现其他更喜欢其中一种功能的规则。


根据当前的 C++ 工作草案进行分解

初始化器[dcl.init]

在这两种情况下

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

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

  • T候选者的转换构造函数( [over.match.copy]/1.1 )
    • bar::bar(const foo& foo);是候选人
  • 初始化表达式的类型是_cv_ S这样的,因此考虑非显式转换函数:( [over.match.copy]/1.2 )
    • foo::operator bar() const不隐藏在foo或 之内const foo,并且产生bar与 相同的结果T,因此是候选者。

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

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

在这两种情况下,我们都有一个用户定义的转换,其中包括:

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

如果我们选择构造函数,“结果类型”是“目标类型的 cv 未限定版本的纯右值,其结果对象由构造函数初始化”( [dcl.init]/17.6.3 ),因此对于两个候选函数中,第二个标准转换是Identity ( bar-> bar)。

过载解析[over.match]

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

根据[dcl.init]/17.6.3foo ,在两种情况下,初始化表达式将分别成为所选调用的参数const foo

bar::bar(const foo& foo)

foo::operator bar() const

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

两者都是Identity => User Defined Conversion => Identity,即都是用户定义的转换序列

排名转换序列over.ics.rank

我们可以在序列之间建立一个排名吗?仅当以下情况之一适用时

转换序列是无法区分的,即没有更好也没有更差

最佳可行功能over.match.best

这两个函数是“更好”的函数吗?仅当以下情况之一适用时

两者都不是“更好”的函数,因此调用格式不正确[超过匹配最佳]/2