joe*_*ech 11 c++ c++20 std-ranges
我有一段使用 C++20 范围库的代码,取自此 SO anwer。该代码被某些编译器(版本)拒绝,并且某些较旧的 GCC 版本返回垃圾。哪个编译器是正确的?
该代码应该打印 a 中第一列的元素std::vector<std::vector>。
#include <vector>
#include <string>
#include <ranges>
#include <iostream>
int main()
{
// returns a range containing only the i-th element of an iterable container
auto ith_element = [](size_t i) {
// drop the first i elements in the range and take the first element from the remaining range
return std::views::drop(i) | std::views::take(1);
};
// returns a range over the i-th column
auto column = [ith_element](size_t i) {
return std::views::transform(ith_element(i)) | std::views::join; // returns a range containing only the i-th elements of the elements in the input range
};
std::vector<std::vector<std::string>> myvec = {
{ "a", "aaa", "aa"},
{"bb", "b", "bbbb"},
{"cc", "cc", "ccc"}
};
for (auto const& v: myvec | column(0)){
std::cout << v << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于海湾合作委员会 10.1、10.2、10.3、10.4:
b
Run Code Online (Sandbox Code Playgroud)
无法使用 GCC 11.1 和 clang 进行编译。
error: no match for 'operator|' (operand types are 'std::vector<std::vector<std::__cxx11::basic_string<char> > >' and 'std::ranges::views::__adaptor::_Pipe<std::ranges::views::__adaptor::_Partial<std::ranges::views::_Transform, std::ranges::views::__adaptor::_Pipe<std::ranges::views::__adaptor::_Partial<std::ranges::views::_Drop, long unsigned int>, std::ranges::views::__adaptor::_Partial<std::ranges::views::_Take, int> > >, std::ranges::views::_Join>')
Run Code Online (Sandbox Code Playgroud)
a
bb
cc
Run Code Online (Sandbox Code Playgroud)
在 GCC 11.2、11.3、12.1、12.2、MSVC 19.33 上按预期工作
cpp*_*ner 10
GCC 11.2、11.3、12.1、12.2、MSVC 19.33 是正确的。
Clang up to 15 根本不支持 libstdc++ <ranges>,而使用 libc++ 程序可以正常工作。
GCC 10.1、10.2、10.3、10.4 和 11.1std::views::drop(i)中使用的错误处理ith_element(i)。
下面是为什么std::views::drop(i)很复杂,以及 GCC 是如何做错的:
为了range | std::views::drop(i)工作, 的结果std::views::drop(i)必须记住 的值i。但它应该存储 的副本i还是对 的引用i?
当参数是左值时,GCC 10.x 存储引用。因此,对于 GCC 10.x,返回的结果return std::views::drop(i) | std::views::take(1);包含悬空引用。
GCC 11.1 实现了P2281R1 澄清范围适配器对象,这使得此类对象始终存储参数的副本。
是用大括号 ( ) 还是用小括号 ( )range | std::views::drop(i)初始化结果?std::ranges::drop_view{range, i}std::ranges::drop_view(range, i)
的相关构造函数drop_view是drop_view(V, range_difference_t<V>). 请注意,第二个参数是有符号整数类型,并且列表初始化不允许无符号到有符号的转换(因为它是缩小转换)。因此,使用大括号时,相应的参数不能是无符号整数(例如size_t)。
GCC 10.x 以某种方式允许这种转换,而 GCC 11.1(实现了 P2281R1)则拒绝它。因此,在 GCC 11.1 中,当is时,使用 ofstd::views::drop(i)始终是错误。isize_t
GCC 11.2 和 12 实现P2367R0 从第 24 条中删除列表初始化的误用,更改std::views::drop为使用括号而不是大括号,从而允许从size_t到差异类型的转换。
| 归档时间: |
|
| 查看次数: |
742 次 |
| 最近记录: |