为什么 GCC 会将这个向量构造函数的参数转发给所包含类型的构造函数,而 Clang 却不会?

问题描述 投票:0回答:1

考虑以下虚拟类型:

struct Foo{
Foo(int x) : x{x}{}

template<std::ranges::range R>
Foo(R r) : x{std::accumulate(r.begin(), r.end(), 0, [](int x, const auto& foo){return x + foo.x;})}{}

int x;
};

如果我现在用另一个

std::vector<Foo>
初始化一个
std::vector<Foo>
,结果会因编译器而异。

std::vector<Foo> foos{Foo{1}, Foo{2}, Foo{3}};
std::vector<Foo> foos_copy{foos};

在 clang

foos == foos_copy
中,GCC 将向量转发到
Foo
的基于范围的构造函数,导致
foos_copy
仅包含单个元素,就好像它曾经是

std::vector<Foo> foos_copy{{foos}};

请参阅此处查看完整示例:https://godbolt.org/z/G1dhbKsoc

我只是想知道为什么存在这种差异以及哪个编译器是正确的。

c++ g++ clang++
1个回答
0
投票

CWG2137 更改了类类型自身类型的列表初始化规则。以前,复制/移动构造函数优先。现在,

std::initializer_list
构造函数优先,但如果不存在可行的构造函数,那么它仍然会退回到复制/移动构造函数(或可以接受相同类型的其他构造函数)。

这个问题很奇怪,因为该决议是在 2016 年通过的,但该问题的提交者和 Clang 的主要贡献者 Richard Smith 并没有在 Clang 中实际执行该决议。我问理查德是否是因为他尝试实现它并发现它破坏了太多代码,但他没有回答。我看到最近努力在 Clang 中实现它,但它在合并后 5 天就被恢复了,这可能没有足够的时间让外部用户报告回归。

无论如何,标准规定

foos_copy
最终应该只有 1 个元素,并且取决于你如何看待它,要么 Clang 尚未实现它,要么决议本身是错误的,最终需要恢复。 (请注意,与 user17732522 在评论中所说的相反,CWG2742 并没有主张恢复 CWG2137。相反,CWG2742 拟议决议的作者不小心写了将恢复 CWG2137 的措辞。)

© www.soinside.com 2019 - 2024. All rights reserved.