我发现gcc-8和clang-6的逻辑不一致.
这发生在一个真正的代码库中,当我使用clang开发时,我使用gcc进行部署。
请告知哪个编译器是错误的,以便我可以适当地提交一个错误。
提要
A可以隐式转换为B,A可以从A (复制/移动)和std::initializer_list<B>构建。
从A初始化A&&时
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
发布于 2019-02-01 11:07:17
标准草案(T is thing) [dcl.init.list]
列表初始化是从大括号内的列表中初始化对象或引用...。 列表-对象或T类型引用的初始化定义如下:
std::initializer_list<E>的专门化,则不适用当对非聚合类类型T的对象进行列表初始化以使dcl.init.list指定根据本项中的规则执行重载解析时,重载解析将分两个阶段选择构造函数:
如果初始化程序列表没有元素,而T具有默认构造函数,则省略第一阶段。不适用
返回到dcl.init.list,了解https://timsong-cpp.github.io/cppwp/n4659/dcl.init#list-2是什么:
如果构造函数的第一个参数是
std::initializer_list<E>类型,或者引用了某些类型E的cv限定的std::initializer_list<E>,并且没有其他参数,或者所有其他参数都具有默认参数(dcl.fct.default),则构造函数就是初始化-列表构造函数。
还有一个方便的说明,重申了这一结论:
注意:在列表初始化中,初始化-列表构造函数比其他构造函数更受青睐。
我的结论是:
应首先考虑初始化项-列表构造函数候选项,并在其有效时使用。当thing隐式转换为thing_ref时,它应该是有效的。在我看来,GCC是在服从。
如果要初始化具有初始化程序-列表构造函数的类型对象,但不想使用该构造函数,则不要使用列表初始化,即不要使用大括号-init- list。
https://stackoverflow.com/questions/54476572
复制相似问题