当我试图支撑 std :: vector< foo>
的同事时,我的一位同事发现了与GCC的奇怪汇编错误提供了一个模板构造函数,例如在以下示例中:(
#include <vector>
struct Foo{
template <class T> Foo(T) {}
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
};
int main(){
std::vector<Foo> v1(std::vector<Foo>{}); // ok
std::vector<Foo> v2{std::vector<Foo>{}}; // compilation error
}
请参阅 Compiler Explorer 。)
IS这是一个错误吗?如果是这样,(我想在实例化过程中)在哪里犯错了?换句话说,由于所有三个编译器的代码都可以,一旦删除了模板的约束,后者的旅行gcc中会有什么?
A colleague of mine has find a strange compilation error with GCC when one tries to brace initialize a std::vector<Foo>
with another, if Foo
is move-only but provides a templated constructor, like in the following example:
#include <vector>
struct Foo{
template <class T> Foo(T) {}
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
};
int main(){
std::vector<Foo> v1(std::vector<Foo>{}); // ok
std::vector<Foo> v2{std::vector<Foo>{}}; // compilation error
}
(See code and error on Compiler Explorer.)
Is it a bug? If so, where (within the instantiation process, I guess) is GCC making the mistake? In other words, since the code is ok for all three compilers as soon as one removes the templated construtor, what in the latter trips GCC up?
发布评论
评论(2)
如果我们停止使用向量,以便可以看到正在使用哪些构造函数,那么也许会更清楚地发生了什么。
https://godbolt.org/z/z/9qs9bvjjz
; foo&gt; 从
v&lt; foo&gt;
使用()
和{}
。要使用GCC和Clang创建
V1
,我们获得了“ V复制”,请将v选择为最佳的V ctor。对于v2
,我们也会获得“ V复制”,但是对于GCC,我们获得了“ V list&lt; foo&gt;”。它使用V的初始化列表构造函数,而不是复制构造函数。现在,应该想知道,我们如何从
v&lt; foo&gt;
的一个元素的列表中获取std :: prinitizer_list&lt; foo&gt;
?这是因为foo
的模板构造函数,它提供了转换构造函数,可以从v&lt; foo&gt;
中创建foo
。海湾合作委员会的行为与我们写的一样:
我认为海湾合作委员会在这里是正确的。
v&lt; foo&gt; v2 {v1}
是直接列表initialization,分辨率分为两个阶段。第一个是仅考虑std :: prinitizer_list
构造函数,然后第二个是将所有构造函数视为参数。第一阶段应通过将v1
转换为foo
来产生匹配,这就是GCC选择的。如果尚不清楚,一旦选择了initializer_list构造函数,则您会出现矢量错误,因为不可能将构造函数与不可复制对象列表一起使用。 initializer_list的元素是const,并且向量从中被复制。
If we stop using vector so we can see what constructors are getting used, then maybe it gets more clear what's going on.
https://godbolt.org/z/9qs9bvjjz
Now let's try to copy construct a
V<Foo>
from aV<Foo>
, using both()
and{}
.To create
v1
with both gcc and clang, we get "V Copy", copy ctor of V chosen as best. Forv2
on clang we get "V Copy" as well, but for gcc, we get "V list<Foo>". It's using the initializer list constructor of V instead of the copy constructor.Now, one should wonder, how did we get a
std::initializer_list<Foo>
from a list of one element ofV<Foo>
? That's because of the template constructor ofFoo
, which provides a conversion constructor to allow creating aFoo
from aV<Foo>
.gcc acts the same as if we had written:
I think gcc is correct here.
V<Foo> v2{v1}
is direct-list-initialization and the resolution is done in two phases. The first is to consider onlystd::initializer_list
constructors, then the second is to consider all constructors with the list as the arguments. The first phase should produce a match, by convertingv1
into aFoo
, and that's what gcc picks.In case it's not clear, once the initializer_list constructor is chosen, you get an error with vector because it's not possible to use that constructor with a list of non-copyable objects. The initializer_list's elements are const and the vector is copy-initialized from it.
我认为, GCC在拒绝程序的情况下是正确的:
std :: vector
具有构造函数 采用std :: pritializer_list
code :当您写作时:
在上述语句中,引用的初始化器列表ctor ctor
vector
可以使用/使用。此外,复制构造函数
foo :: foo(const foo&amp;)
将在此处使用,因为来自 dcl.init.lst :(强调矿山)
但是,由于复制构造函数为
已删除
,我们会得到上述错误。您可以通过默认
复制ctor而不是按照来确认确实是这种情况。 “>此演示,我们可以注意到那里 nockiles(compiles)问题。I think that GCC is correct in rejecting the program for the reasons described below:
std::vector
has a constructor that takes anstd::initializer_list
:Thus when you wrote:
In the above statement, the quoted initializer list ctor of
vector
can be used/utilised.Moreover, the copy constructor
Foo::Foo(const Foo&)
will be used here since from dcl.init.lst:(emphasis mine)
But since the copy constructor is
deleted
we get the mentioned error. You can confirm that this is indeed the case bydefaulting
the copy ctor instead of deleting it as done in this demo and as we can notice there the program works(compiles) without any issues.