5 c++ language-lawyer implicit-conversion c++11
以下代码工作正常:
#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()
{
}
Run Code Online (Sandbox Code Playgroud)
并产生输出:
A(int, int)
Run Code Online (Sandbox Code Playgroud)
但我不明白为什么?标准说的是:
但是,当考虑构造函数或用户定义的转换函数的参数时,如果在类复制初始化的第二步中复制/移动临时函数时,通过13.3.1.3调用该函数,则通过13.3.1.7传递时初始化程序列表作为单个参数,或者当初始化程序列表只有一个元素并且转换为某个类X或引用(可能是cv限定的)时,X仅被视为X [...]的构造函数的第一个参数考虑标准转换序列和省略号转换序列
所以在我们的例子中,我们考虑了构造函数的参数(它是{B(), B()}).更确切地说,我们将initializer-list作为单个参数传递(我引用的规则中的第二个案例).现在,我们需要将initializer-list的第一个元素(临时类型B)转换为int,并且唯一的方法是应用用户定义的convertion(B::operator int()).但是,正如在规则末尾所说的那样,我只引用标准转换序列和省略号转换序列.因为,该代码不起作用,它应该抛出A(int, int)不可行或类似的错误.
怎么了.可能是一个错误?
该措辞有缺陷,并随 C++14 进行了更改。现在[over.best.ics]/4 阅读
\n\n\n\n\n然而,如果目标是
\n\n\n
\n\n- 构造函数的第一个参数或
\n- [\xe2\x80\xa6]
\n并且构造函数或用户定义的转换函数是候选\n
\n\n\n
\n\n- 13.3.1.3,当参数是类复制初始化第二步中的临时参数时,
\n- 13.3.1.4、13.3.1.5 或 13.3.1.6(所有情况),或
\n- 13.3.1.7 的第二阶段,当初始值设定项列表只有一个元素,并且目标是 class 的 a\n 构造函数的第一个参数
\nX,并且转换为X或引用\n (可能是 cv 限定的)X,不考虑用户定义的转换序列。[注意:这些规则可防止在重载决策期间应用多个用户定义的转换,从而避免无限递归。\xe2\x80\x94\n 尾注]
\n
B()to的转换int不在此范围内 - 粗体短语仅适用于在复制初始化期间将引用绑定到临时对象。
然而, Clang根据上面的内容拒绝了这个示例代码:
class A;\n\nstruct B\n{\n operator A();\n};\n\nstruct A\n{\n A(A const&){}\n};\n\nA a{B()};\nRun Code Online (Sandbox Code Playgroud)\n