c++ - clang 和 gcc 为相同的代码生成不同的逻辑。哪个是对的?
问题描述
我发现 gcc-8 和 clang-6 产生的逻辑之间存在差异。
这发生在一个真实的代码库中,当我使用 clang 开发时,我使用 gcc 部署。
请告知哪个编译器有错误,以便我可以适当地提交错误。
概要
A
可隐式转换为B
A
可从A
(copy/move) 和std::initializer_list<B>
.
A
从初始化 an时A&&
:
- clang 选择移动构造函数
- gcc 选择
initializer_list
构造函数。
现场演示:https ://coliru.stacked-crooked.com/a/bc50bd8f040d6476
MCVE
#include <initializer_list>
#include <utility>
#include <iostream>
struct thing;
struct thing_ref
{
thing_ref(thing&& other) : ref_(other) {}
thing_ref(thing& other) : ref_(other) {}
thing& ref_;
};
struct thing
{
thing() {}
thing(std::initializer_list<thing_ref> things)
{
std::cout << "initializer_list path\n";
}
thing(thing&& other)
{
std::cout << "move path\n";
}
thing(thing const& other)
{
std::cout << "copy path\n";
}
};
struct foo
{
foo(thing t) : mything { std::move(t) } {}
thing mything;
};
int main()
{
thing t;
auto f = foo { std::move(t) };
}
编译器设置:
没什么特别的,根据 coliru 链接:-std=c++17 -O2
解决方案
标准草案(T
是thing
)[dcl.init.list]:
列表初始化是从一个花括号初始化列表初始化一个对象或引用。...
类型 T 的对象或引用的列表初始化定义如下:
如果花括号初始化列表包含指定初始化列表 [不适用]
如果 T 是一个聚合类并且[不适用]
否则,如果 T 是字符数组[不适用]
否则,如果 T 是一个聚合[不适用]
否则,如果初始化列表没有元素[不适用]
否则,如果 T 是
std::initializer_list<E>
[不适用]的特化否则,如果 T 是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议选择最佳构造函数[适用]
...
当非聚合类类型 T 的对象被列表初始化,使得 [dcl.init.list] 指定根据本节中的规则执行重载解析时,重载解析分两个阶段选择构造函数:
最初,候选函数是类 T 的初始化列表构造函数([dcl.init.list]),参数列表由初始化列表作为单个参数组成。[适用]
如果没有找到可行的初始化列表构造函数,则再次执行重载决议,其中候选函数是类 T 的所有构造函数,参数列表由初始化列表的元素组成。
如果初始化列表没有元素并且 T 有默认构造函数,则省略第一阶段。[不适用]
返回 [dcl.init.list] 以了解什么是初始化列表构造函数:
一个构造函数是一个初始化列表构造函数,如果它的第一个参数的类型
std::initializer_list<E>
或引用可能std::initializer_list<E>
是某个类型 E 的 cv 限定的,并且要么没有其他参数,要么所有其他参数都有默认参数([dcl.fct.default] )。
还有一个方便的注释,重申了结论:
注意:初始化列表构造函数比列表初始化中的其他构造函数更受青睐
我的结论:
应首先考虑初始化列表构造函数候选者,并在其有效时使用。由于thing
隐式转换为thing_ref
,它应该是有效的。在我看来,GCC 符合要求。
如果要初始化具有初始化列表构造函数的类型的对象,但不想使用该构造函数,则不要使用列表初始化,即不要使用大括号初始化列表。
推荐阅读
- php - 解析错误:语法错误,第 601 行 C:\xampp\php\pear\HTML\QuickForm.php 中的意外“新”(T_NEW)
- javascript - 通过单击按钮更改整个 CSS
- python - 查找最接近 0 的值的索引时出错
- pyspark - pyspark 累积计数不同
- css - 允许在图像上分层外观的 v-avatar 填充?
- c - c中的可变长度格式字符串
- bash - 为什么打包为 .app 与直接以 .sh 运行时,脚本的功能会有所不同?
- c# - 数据绑定 MSChart 未更新
- c# - API 结果填充 Json 中所有嵌套的不必要类(重复父级)
- arrays - 尝试搜索数组的值并在找到时更改值