为什么在初始化期间应用用户定义的转换

Why does user-defined conversion applied during the initialization?

本文关键字:用户 定义 转换 应用 初始化 为什么      更新时间:2023-10-16

以下代码工作正常:

#include <iostream>
struct B
{
    operator int()
    {
        return int();
    }
};
struct A
{
    A(int, int){ std::cout << "A(int, int)" << std::endl; }
};
A a({B(), B()});
int main()
{ 
}

并产生输出:

A(int, int)

演示

但我不明白为什么?标准说的是:

但是,当考虑构造函数或 用户定义的转换函数,在 13.3.1.3 中是候选函数,当 在第二步中为复制/移动临时而调用 类复制初始化,传递初始值设定项时由 13.3.1.7 列表作为单个参数或当初始值设定项列表只有一个参数时 元素并转换为某个类 X 或引用(可能 符合 cv 标准(X 被视为构造函数的第一个参数 的 X [...] 仅考虑标准转换序列和省略号转换序列

所以在我们的例子中,我们考虑了构造函数的参数(它是{B(), B()}(。更准确地说,我们将初始值设定项列表作为单个参数传递(我引用的规则中的第二种情况(。现在,我们需要将初始值设定项列表的第一个元素(临时类型为 B(转换为 int,唯一的方法是应用用户定义的转换 ( B::operator int() (。但是,正如规则末尾所说,我只引用了标准转换序列,并且考虑了省略号转换序列。由于该代码不应该工作,因此它应该抛出错误,例如A(int, int)不可行或某种错误。

怎么了。可能是错误?

措辞有缺陷,并随着 C++14 而更改。现在 [over.best.ics]/4 读取

但是,如果目标是

  • 构造函数的第一个参数或
  • [...]

并且构造函数或用户定义的转换函数是候选函数 由

  • 13.3.1.3,当参数是类复制初始化第二步中的临时参数时
  • 13.3.1.4、13.3.1.5或
  • 13.3.1.6(在所有情况下(,或
  • 13.3.1.7 的第二阶段,当初始值设定项列表只有一个元素时,目标是 类 X 的构造函数,并且转换是 X 或引用 (可能符合简历标准( X

不考虑用户定义的转换序列。[ 注:这些 规则阻止应用多个用户定义的转化 在重载解析期间,从而避免无限递归。— 尾注 ]

这不包括将B()转换为int - 粗体短语仅适用于在复制初始化期间绑定对临时引用的引用。
但是,Clang 根据上述内容拒绝了此示例代码:

class A;
struct B
{
    operator A();
};
struct A
{
    A(A const&){}
};
A a{B()};