我想使用范围将跨度中包含的四个字节转换为字符串。这是输入和输出的示例:
std::span<std::byte> data{bytes}; // contains 0x11, 0x22, 0x33, 0x44
std::string result = ...; // results in 44:33:22:11
Run Code Online (Sandbox Code Playgroud)
这是我根据range-v3 how to action::join with delimiter 的答案得出的结论:
auto const result = data
| views::reverse
| views::transform([](std::byte byte) { return fmt::format("{:02x}", byte); })
| views::join(':');
Run Code Online (Sandbox Code Playgroud)
然而,它无法编译,并出现一个非常......让我们说详细的错误:
file.cpp: In function 'my_function {anonymous}::decode_function(std::span<const std::byte>)':
file.cpp:87:21: error: no match for call to '(const std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::<lambda(_Range&&)> >) (char)'
87 | | views::join(':');
| ^
In file included from file.cpp:3:
/usr/include/c++/10/ranges:1157:4: note: candidate: 'constexpr auto std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>::operator()(_Range&&) const [with _Range …Run Code Online (Sandbox Code Playgroud) 当我使用 Stream Library ( http://jscheiny.github.io/Streams/api.html# ) 时,我可以像在 Java-Streams 中那样做类似的事情:
#include "Streams/source/Stream.h"
#include <iostream>
using namespace std;
using namespace stream;
using namespace stream::op;
int main() {
list<string> einkaufsliste = {
"Bier", "Käse", "Wurst", "Salami", "Senf", "Sauerkraut"
};
int c = MakeStream::from(einkaufsliste)
| filter([] (string s) { return !s.substr(0,1).compare("S"); })
| peek([] (string s) { cout << s << endl; })
| count()
;
cout << c << endl;
}
Run Code Online (Sandbox Code Playgroud)
它给出了这个输出:
Salami
Senf
Sauerkraut
3
Run Code Online (Sandbox Code Playgroud)
在 C++20 中,我发现了范围,它看起来很有希望实现同样的目标。但是,当我想构建类似的函数式编程风格时,它不起作用:
Salami
Senf
Sauerkraut
3 …Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
#include <vector>
#include <algorithm>
#include <ranges>
#include <cassert>
// The type is defined in legacy code and we can not change it
struct A
{
int a;
};
bool operator <(const A &a1, const A &a2)
{
return a1.a < a2.a;
}
int main()
{
assert(A {} < A{}); // OK
std::vector<A> c;
assert(std::ranges::is_sorted(c)); // compilation error
}
Run Code Online (Sandbox Code Playgroud)
可以通过将“spaceship”比较运算符添加到 A 来修复代码:
auto operator<=>(const A &) const = default;
Run Code Online (Sandbox Code Playgroud)
但是,在类外部定义它适用于第一个assert,但不适用于第二个:
auto operator <=>(const A &a1, const A &a2) …Run Code Online (Sandbox Code Playgroud) 我想将范围拆分{1, 2, 3, 4, 5}为 <任何大小>的子范围范围(例如,大小为 2: {{1, 2}, {3, 4}, {5}})。但std::views::split只能按分隔符拆分。
是否没有标准的“反向连接”或其他方法可以做到这一点?
在这样的情况下:
auto pow = [](int i) {return i * i; };
auto closure = ranges::views::transform(pow);
Run Code Online (Sandbox Code Playgroud)
closure似乎是一个view_closure. 我确实知道最后一行没有多大意义,因为变换没有应用于任何地方。实际上,我也可以将向量输入x其中closure,它既可以编译又可以正常工作。
但是,什么是视图关闭?它是一个“类似函数”的对象,希望在某个地方应用吗?它的语义是什么?
我从 Eric Niebler 的源代码中找到了这一点range-v3,但在其他地方没有任何文档指定它。
我什至不知道view_closure是供内部使用还是供用户使用。
考虑以下代码,它使用 C++20 中的 Ranges 库:
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> v{0,1,2,3,4,5,6,7};
auto transformed = std::ranges::views::transform(v, [](int i){ return i * i; });
std::cout << *std::prev(std::end(transformed));
}
Run Code Online (Sandbox Code Playgroud)
得知(至少在 GCC-10.3.0 和 GCC-12.0.0 下)这段代码卡在std::prev.
什么情况是,由于拉姆达不返回左值引用,transformed范围迭代器被列为输入迭代器(参见规则进行iterator_category选择的views::transform)。但是,std::prev 要求迭代器至少是双向迭代器,所以我猜这段代码实际上是UB。在 libstdc++ 中,应用于std::prev输入迭代器会导致此函数
template<typename _InputIterator, typename _Distance>
__advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_assert(__n >= 0);
while (__n--)
++__i;
}
Run Code Online (Sandbox Code Playgroud)
被调用__n == -1 …
代码显示了我的问题,我不能使用take(3)之后istream_view。
错误信息是:
/home/linuxbrew/.linuxbrew/Cellar/gcc/11.1.0_1/include/c++/11.1.0/ranges:1775:48: 错误:传递 'std::ranges::take_view<std::ranges::transform_view< std::ranges::basic_istream_view<int, char, std::char_traits >, int ( )(int)> >::_CI' {aka 'const std::counted_iterator<std::ranges::transform_view<std:: range::basic_istream_view<int, char, std::char_traits >, int ( )(int)>::_Iterator >'} 作为 'this' 参数丢弃限定符 [-fpermissive] 1775 | { 返回 __y.count() == 0 || __y.base() == __x._M_end; }
#include <ranges>
using namespace std::views;
using namespace std::ranges;
int to_sq(int a){return a*a;}
int main()
{
auto m_range = istream_view<int>(std::cin);
// error
for (auto i : m_range | transform(to_sq)|take(3))
{
std::cout << i << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud) 从 C++23 开始,views 不再需要是default_constructible。对于诸如views::filter和 之类的范围适配器views::transform,它们的默认构造函数被重新定义为:
template<input_\xc2\xadrange V, indirect_\xc2\xadunary_\xc2\xadpredicate<iterator_t<V>> Pred>\n requires view<V> && is_object_v<Pred>\nclass filter_view : public view_interface<filter_view<V, Pred>> {\nprivate:\n V base_ = V(); // exposition only\n copyable-box<Pred> pred_; // exposition only\npublic:\n filter_view() requires default_\xc2\xadinitializable<V> && default_\xc2\xadinitializable<Pred> = default;\n};\nRun Code Online (Sandbox Code Playgroud)\n并且因为p2325r3ref_view中已删除 的默认构造函数,这表明不再适用于左值的范围适配器:rangestd::vector default_constructible
std::vector v{1, 2, 3};\nauto r = v | std::views::filter([](auto) { return true; });\ndecltype(r){}; // ok in C++20, error in C++23\n …Run Code Online (Sandbox Code Playgroud) 让我有一个代码:
for (auto& a : x.as)
{
for (auto& b : a.bs)
{
for (auto& c : b.cs)
{
for (auto& d : c.ds)
{
if (d.e == ..)
{
return ...
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
as, bs, cs, ds - 相应元素的 std::vector。
是否可以使用 std::ranges 将四个丑陋的循环转换为一个漂亮的单行表达式?
c++ ×10
std-ranges ×10
c++20 ×9
c++23 ×1
iterator ×1
nested-loops ×1
range ×1
range-v3 ×1
standards ×1
stl ×1