Fed*_*dor 5 c++ initializer-list language-lawyer overload-resolution
在下面的代码中,struct A有两个构造函数:A(int)和A(std::initializer_list<char>)。然后使用以下命令创建该结构的对象A({0}):
#include <initializer_list>
struct A {
int a;
constexpr A(int) { a = 1; }
constexpr A(std::initializer_list<char>) { a = 2; }
};
static_assert( A({0}).a == 2 );
Run Code Online (Sandbox Code Playgroud)
事实证明,GCC 和 Clang 更喜欢这里的构造函数initializer_list(尽管int必须在 中转换参数char)并且整个程序被接受,但 MSVC 选择A(int)构造函数,导致static_assert. 演示: https: //gcc.godbolt.org/z/qx7W417Mv
这里是哪个编译器?
这是CWG 1589:
\n\n\n1589. 列表初始化序列的排序不明确
\n部分: 16.3.3.2 [over.ics.rank]
\n
\n状态:CD4
\n提交者:Johannes Schaub
\n日期:2012-11-21[在 2014 年 11 月的会议上移至 DR。]
\n在当前的措辞中,以下示例的解释不清楚:
\nRun Code Online (Sandbox Code Playgroud)\nvoid f(long);\nvoid f(initializer_list<int>);\nint main() { f({1L});\n问题是列表初始化序列也可以是标准转换序列,具体取决于元素的类型和参数的类型,因此列表中的项目符号不只一个, \n16.3.3.2 [over.ics .rank] 第 3 段适用:
\n\n\n[...]
\n这些项目符号为上面的示例提供了相反的结果,并且存在\n选择的实现差异。
\n[...]
\n拟议决议(2014 年 6 月):
\n此问题已通过问题\n 1467的解决方案得到解决。
\n
根据该决议,该决议已通过CWG 1467解决:
\n\n\n1467. 来自相同类型对象的聚合的列表初始化
\n[...]
\n拟议决议(2014 年 6 月):
\n[...]
\n\n
\n- 将 16.3.3.2 [over.ics.rank] 第 3 段的最后一个项目符号移至列表的开头,并将其更改如下:
\n[...]
\n即使本款中的其他规则之一将适用。[示例: ... \xe2\x80\x94结束示例]
\n该决议还解决了问题 1490、1589、1631、1756 和 1758。
\n
特别是通过重新排序[over.ics.rank]/3,使得[over.ics.rank]/3.1现在适用于 OP 的情况,并优先于[over.ics.rank的其他规则]/3:
\n\n\n列表初始化序列
\nL1是比\n列表初始化序列更好的转换序列,L2如果\n
\n- (3.1.1)
\nL1转换为std\xe2\x80\x8b::\xe2\x80\x8binitializer_\xc2\xadlist<X>对于某些X且不L2,或者,如果不是- (3.1.2) [...]
\n即使本款中的其他规则之一将适用。
\n
GCC 和 Clang 等编译器已将 DR 1467 向后移植到早期标准(C++11 和 C++14);具体从 Clang 3.7 开始,我们可以验证 CWG 1589 与 OP 示例的连接,因为它被 Clang 3.6 拒绝,但被 Clang 3.7 接受(DEMO)。
\n另一方面,MSVC 似乎尚未实现此更改,即使根据更新的 C++17 标准,它不再“只是一个”DR。
\n| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |