代码如下。
struct A {
A() {}
};
struct B {
B() {}
explicit operator A() { return A{}; }
};
struct C {
A a;
C(B b) : a{b} {}
};
我有一个struct A
,它不是可聚合构造的(因为它定义了一个构造函数)。 struct B
也是如此。但它也有一个显式的用户定义转换运算符struct A
。现在struct C
的构造函数使用struct B
,并使用它来构造struct A
。与cppreference一样,转换运算符可以参与直接初始化,我认为struct C
的成员初始化就是这种情况。它传递给GCC 5.2(C ++ 11)。但是它在Clang 3.6上失败了。我尝试使用C ++ 11,C ++ 14和C ++ 1z。
如果我将a{b}
更改为a(b)
,则会传递给Clang和GCC。
我想知道这是一个Clang bug还是我误解了标准?
答案 0 :(得分:1)
由于DR1467(cfr。22259),clang最近发生了变化
gcc和clang的最新版本都做了正确的事情:编译你的代码没有错误。
在成员初始化程序列表的第一轮重载解析中,A的构造函数被丢弃,因为它们不是初始化列表构造函数。
之后 [over.match.list] / p1 接管
- 如果找不到可行的初始化列表构造函数,则重载解析 再次执行,其中候选函数都是 类T的构造函数和参数列表由 初始化列表的元素。
这次A的构造函数被考虑在内。 A的复制和移动构造函数具有足够的参数来匹配重载解析过程,并且它们不会导致任何用户定义的转换抑制,因为13.3.1.3甚至13.3.1.7(仍在Clang's code中)不适用于这些构造
因此,它们已输入重载分辨率集, [over.best.ics] 适用。