重载分辨率:是否首选直接转换运算符(由于复制省略)?
Overload-Resolution: Is a direct conversion operator preferred (as a consequence of copy-elision)?
给定
struct E
{
};
struct P
{
explicit P(E) {}
};
struct L
{
operator E() {return {};}
operator P() {return P{E{}};}
};
根据C++17语言标准,表达式P{L{}}
编译吗?
不同的编译器产生不同的结果:
- 海湾合作委员会(后备箱):确定
- GCC 8.3:错误(过载不明确)
- GCC 7.4:确定
- 叮当(树干):好的
- 叮当 8.0.0:确定
- 叮当 7.0.0:确定
- MSVC v19.20:错误(过载不明确)
- ICC 19.0.1:错误(多个构造函数实例匹配)
我认为根据标准的正确行为是模棱两可的。
[dcl.init]/17.1:
如果初始值设定项是(非括号)大括号初始化列表或 is = 大括号初始化列表,则对象或引用是列表初始化的。
[dcl.init.list]/3.6:
否则,如果 T 是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载解析([over.match]、[over.match.list])选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则程序格式不正确。
[over.match.list] 只是谈论选择一个构造函数。我们有两个可行的选择:通过L{}.operator E()
P(E)
和P(P&&)
(隐式移动构造函数)通过L{}.operator P()
。没有一个比另一个更好。
但是,这很容易让人想起CWG 2327:
struct Cat {}; struct Dog { operator Cat(); }; Dog d; Cat c(d);
正如问题所表明的那样,当前调用Cat(Cat&&)
而不仅仅是d.operator Cat()
,并建议我们实际上也应该考虑转换函数。但这仍然是一个悬而未决的问题。我不确定 gcc 或 clang 在回应这个问题时做了什么(或者回应首先提出的类似例子),但根据您的结果,我怀疑他们认为直接转换函数L{}.operator P()
是一个更好的匹配,然后就这样做。
相关文章:
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 适用于大型数组的无复制线程安全环形缓冲区
- 复制构造函数优先于移动构造函数
- Qt5 复制(复制)可执行文件
- 复制<Interface>作用类似于值的类的shared_ptr
- 保证复制 elis 是否适用于函数参数?
- 复制 std::vector,但将 lambda 应用于每个元素
- 对C++所做的更改使复制初始化适用于具有显式构造函数的类
- 使用std ::复制复制阵列时获取细分故障
- 当涉及分配器时,是否有类似于复制和交换习惯用法的东西
- 移动构造函数相对于复制构造函数的优势是什么?复制构造函数使用bool来表示是复制还是移动
- 对象复制:复制随机引擎的正确方法
- 为什么复制复制的字符串.
- 有效地复制/复制树
- C++ 矢量复制适用于一个向量,但不适用于另一个向量
- 复制省略和返回值优化相对于复制构造函数
- 不依赖于原始的c++复制数组
- 模板构造函数优先于普通复制和移动构造函数
- 作用于可移动但不可复制对象序列的变化STL算法的行为