【问题标题】:Why does user-defined conversion applied during the initialization?为什么在初始化期间应用用户定义的转换?
【发布时间】:2014-12-01 17:06:46
【问题描述】:

以下代码可以正常工作:

#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) 不可行或类似的错误。

怎么了。可能是一个错误?

【问题讨论】:

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


【解决方案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 的第二阶段,初始化器列表只有一个元素,目标是 a 的第一个参数 类X的构造函数,转换为X或引用 (可能有 cv 资格)X,

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

B()int 的转换不在此范围内 - 粗体短语仅适用于复制初始化期间对临时引用的绑定。
不过,Clang rejects this sample code按照上面的说法:

class A;

struct B
{
    operator A();
};

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

A a{B()};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2010-09-30
    相关资源
    最近更新 更多