【发布时间】:2019-02-01 09:30:44
【问题描述】:
我发现 gcc-8 和 clang-6 产生的逻辑有差异。
这发生在一个真实的代码库中,当我使用 clang 开发时,我使用 gcc 部署。
请告知哪个编译器有错误,以便我可以适当地提交错误。
概要
A 可隐式转换为 B
A 可以从 A(复制/移动)和 std::initializer_list<B> 构造。
从A&& 初始化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
【问题讨论】:
-
你用什么标准设置编译?
-
我认为两者都没有错,因为 std::move 是对编译器的建议。 std::move 实际上是一个右值转换。 rvalue 在初始化列表中使用,所以这是正确的。同时它可以移动,所以这也是正确的。不过,我希望这是一个举措。此外,如果您从 foo 中的统一初始化更改,如
mything(std::move(t))中那样,则两者都使用移动构造函数。 -
@bartop 根据 coliru 链接,
-std=c++17 -O2,但-O0也是如此。为了清楚起见,我会更新问题。 -
@Ashkan 编辑代码以删除统一初始化是通过错误修复(经过一段时间追踪错误原因...)
-
@RichardHodges 我的观点是,将统一初始化中的右值视为 initializer_list 是合理的。这可能不是最聪明的,但它是正确的。
标签: c++ language-lawyer c++17