在具有转换运算符的初始化程序的情况下,复制列表初始化的假定行为是什么?
class AAA {
public:
AAA() {}
AAA(const AAA&) {}
};
class BBB {
public:
BBB() {}
operator AAA() { AAA a; return a; }
};
int main() {
BBB b;
AAA a = {b};
}
上面的代码可以在g++和vc++上编译,但不是clang++.
传统语法 AAA a = b;
在所有三个上都可以编译.
The above code compiles on g++ and vc++, but not clang++.
The traditional syntax AAA a = b;
compiles ok on all three.
class AAA {};
class BBB {
public:
BBB() {}
operator AAA() { AAA a; return a; }
};
int main() {
BBB b;
AAA a = {b};
}
以上代码不能在任何 g++、vc++、clang++ 上编译.与第一个代码片段的唯一区别是我删除了两个用户提供的 AAA 构造函数.
同样,传统语法 AAA a = b;
在所有三个上都可以编译.
The above code doesn't compile on any of g++, vc++, clang++. The only difference against the first code snippet is that I removed the two user-provided constructors of AAA.
Again, the traditional syntax AAA a = b;
compiles ok on all three.
我很确定,在带有转换运算符的初始化程序的情况下,复制初始化的传统语法是明确定义的.但是对于 C++11 复制列表初始化,我很困惑.clang 是否采取了正确的措施来拒绝初始化,或者 g++/vc++ 是否采取了正确的措施来接受初始化(如第一个代码片段所示)?为什么像第二个代码片段中所做的这样一个微不足道的更改会导致这种显着不同的行为?在这种情况下,copy-list-initialization 和传统的 copy-initialization 到底有什么区别?
I'm quite sure that the traditional syntax of copy-initialization is well-defined in the case of an initializer with a conversion operator. But for the C++11 copy-list-initialization, I'm confused. Is clang taking the correct action rejecting the initialization or g++/vc++ taking the correct action accepting the initialization (as seen in the first code snippet)? And why such a trivial change as done in the second code snippet will result in that significant different behavior? What's the difference between copy-list-initialization and traditional copy-initialization in this case after all?
添加第三种情况:
class CCC {};
class AAA {
public:
AAA() {}
AAA(const AAA&) {}
AAA(const CCC&) {}
};
class BBB {
public:
BBB() {}
operator CCC() {CCC c; return c;}
};
int main() {
BBB b;
AAA a = {b};
}
上面的代码为所有三个编译器编译.如果最终目标构造函数不是复制构造函数,转换运算符是否有效?
在这种情况下,传统语法 AAA a = b;
无法按预期编译所有三个,因为传统复制初始化最多允许在到达最终副本之前进行一级用户定义的隐式转换构造函数(最终目的地只能是复制构造函数).
The above code compiles for all three compilers. The conversion operator works if the final destination constructor is not the copy constructor?
In this case, the traditional syntax AAA a = b;
fails to compile for all three as expected, since traditional copy-initialization allows one level of user-defined implicit conversion at most before arriving at the final copy constructor (the final destination can only be the copy constructor).
乞求对所有这些混乱的系统解释......
Begging for a systematic explanation for all these mess...
推荐答案
首先,您正在点击 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1673(见最后一个测试用例):如果列表初始化只传递一个元素对于某个类 X
的复制/移动构造函数,不允许在该单个元素上进行用户定义的转换以将其转换为 X
参数.另请参阅 http://llvm.org/bugs/show_bug.cgi?id=12117 制作 Clang执行此规则
For the first, you are hitting http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1673 (see the last testcase): If list initialization passes only a single element to a copy/move constructor of some class X
, user defined conversions are not allowed on that single element to convert it to the X
parameter. Also see http://llvm.org/bugs/show_bug.cgi?id=12117 which made Clang implement this rule
第二个:您正在点击 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467 (但不是使用相同类型的对象,而是使用不相关类型的对象).您的聚合根本不提供 BBB
类型的数据成员.
For the second: You are hitting http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467 (but instead of using an object of the same type, you use an object of an unrelated type). Your aggregate simply doesn't provide a data member of type BBB
.
对于第三种情况:以上两种情况都不适用,所以列表初始化工作并调用AAA
的CCC
构造函数.= b
初始化失败,因为它只允许在单个用户定义的转换序列中尝试将 b
转换为 AAA
.但在这里您需要先转换为 CCC
,然后再转换为 AAA
.对于列表初始化,不存在只进行一次用户定义转换的限制.
For the third: Neither of the above two situations apply, so the list initialization works and calls the CCC
constructor of AAA
. The = b
initialization fails because it is only allowed to try converting the b
to an AAA
in a single user defined conversion sequence. But here you would need to first convert to CCC
and then to AAA
again. For list initialization, this restriction of doing only one user defined conversion does not exist.
相关文章