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

时间:2014-12-01 17:06:47

标签: c++ c++11 language-lawyer implicit-conversion

以下代码可以正常使用:

#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)

DEMO

但我无法理解?标准所说的是:

  

但是,在考虑构造函数的参数时   用户定义的转换函数,它是13.3.1.3时的候选者   在第二步中调用临时复制/移动   通过初始化程序时,通过13.3.1.7进行类复制初始化   列表作为单个参数或初始化列表只有一个   元素和转换到某个类X或引用(可能   cv-qualified)X被认为是构造函数的第一个参数   X [...]只考虑标准转换序列和省略号转换序列

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

出了什么问题。可能是个错误吗?

1 个答案:

答案 0 :(得分:1)

措辞有缺陷并且用C ++ 14改变了。现在[over.best.ics]/4 reads

  

但是,如果目标是

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

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

     
      
  • 13.3.1.3,当参数是类复制初始化的第二步中的临时时,
  •   
  • 13.3.1.4,13.3.1.5或13.3.1.6(在所有情况下)或
  •   
  • 13.3.1.7的第二阶段,当初始化列表只有一个元素时,目标是第一个参数   类X的构造函数,转换为X或引用   (可能是cv-qualified)X
  •   
     

不考虑用户定义的转换序列。 [注意:这些   规则阻止应用多个用户定义的转换   在重载决策期间,从而避免无限递归。 -   结束说明]

B()int的转换不在此范围内 - 粗体短语仅适用于复制初始化期间对临时引用的绑定。
但是,Clang rejects this sample code根据以上内容:

class A;

struct B
{
    operator A();
};

struct A
{
    A(A const&){}
};

A a{B()};