在https://en.cppreference.com/w/cpp/ranges上,std::views::counted列在范围适配器部分中。但是,它没有标记为范围适配器对象。
我想这就是为什么我不能使用管道运算符编写的原因,例如:
std::vector<size_t> vec = {1, 2, 3, 4, 5};
auto view = vec | std::ranges::counted(... ; // does not compile
Run Code Online (Sandbox Code Playgroud)
我的问题是:
#include <iostream>
#include <vector>
#include <ranges>
int main()
{
std::vector<int> ints {1, 2, 3, 4, 5};
auto isEven = [] (const auto& element)
{
return element % 2 == 0;
};
auto even = ints | std::views::filter(isEven);
for (auto& element : even)
{
++element;
}
for (const auto& element : ints)
{
std::cout << element << "\n";
}
std::cout << "\n\n";
// Interesting things start further...
for (auto& element : even)
{
++element;
}
for (const auto& element : ints) …Run Code Online (Sandbox Code Playgroud) 我用 g++ 12.2.1 编译了以下代码:
#include <iostream>
#include <ranges>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> vi;
std::ranges::copy(std::views::istream<int>(std::cin) | std::views::take(3), std::back_inserter(vi));
for (auto i : vi)
std::cout << i << ' ';
}
Run Code Online (Sandbox Code Playgroud)
输入:
1 2 3
4
Run Code Online (Sandbox Code Playgroud)
输出:1 2 3
为什么我必须输入 4 个数字而不是 3 个数字并丢弃最后一个数字?怎么解决?
我想根据某些条件从地图中删除一些元素:
#include <unordered_map>
#include <ranges>
#include <iostream>
int main() {
std::unordered_map<int, int> numbers = {{1,2}, {2,1}, {3,2}, {4,5}};
auto even = [](auto entry){return entry.second %2 == 0;};
for(auto& [key, val] : numbers | std::views::filter(even)) {
numbers.erase(val);
}
for(auto& [key, val] : numbers) {
std::cout << key << " " << val << "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
但似乎我正在使基于范围的循环所需的迭代器无效:
4 5
3 2
1 2
Run Code Online (Sandbox Code Playgroud)
我知道如何使用迭代器显式地执行此操作,但是是否有一种基于范围的简洁方法来删除基于过滤器的元素?
此代码可以正确编译并运行:
\n#include <ranges>\n#include <iostream>\n\nint main() {\n const auto r = std::views::iota(\'a\', static_cast<char>(\'g\' + 1));\n\n for(const auto& [start, end] : r | std::views::chunk(3u)) {\n for(auto it = start; it != end; ++it) {\n std::cout << *it << " ";\n }\n std::cout << "\\n";\n }\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n其输出为:
\na b c \nd e f \ng \nRun Code Online (Sandbox Code Playgroud)\n如果我将定义更改r如下:
a b c \nd e f \ng \nRun Code Online (Sandbox Code Playgroud)\n该代码无法编译。GCC 13 发出以下错误:
\nchunk.cpp:13:21: error: cannot decompose inaccessible …Run Code Online (Sandbox Code Playgroud) 对于std::ranges,为什么transform_view不是bored_range?这是一个简单的示例: https: //godbolt.org/z/14K8Y1xMe及以下:
#include <ranges>
void foo() {
auto i = std::ranges::views::iota(10);
auto t = i | std::ranges::views::transform([](auto v) {return v;});
static_assert(std::ranges::borrowed_range<decltype(i)>);
static_assert(std::ranges::borrowed_range<decltype(t)>);
}
Run Code Online (Sandbox Code Playgroud)
我检查过该基数是借用的范围。是不是功能有问题?文档没有说:https://en.cppreference.com/w/cpp/ranges/transform_view。
使用 C++23,我们可以漂亮地打印范围,目前在{fmt}. 例如,std::set格式为{},而序列容器如std::vector格式为[]。在内部,formatter类模板根据嵌套 typedef 的存在key_type(std::set有或std::vector没有)进行调度。
通过管道将 astd::set插入任何类型view都会删除key_typetypedef 并将其漂亮地打印为std::vector.
#include <ranges>
#include <set>
#include <fmt/ranges.h>
int main()
{
auto s = std::set<int>({ 2, 3, 5, 7 });
fmt::println("{}", s); // nice, formats as { 2, 3, 5, 7 }
fmt::println("{}", s | std::views::reverse); // meh, now uses [] instead of {}
fmt::println("{}", s | std::views::reverse …Run Code Online (Sandbox Code Playgroud) 我一直在尝试一些只是为了好玩,但我偶然发现了以下方法的问题。问题是我在生成的范围内两次得到零值。我错过了什么?我没有正确使用范围还是与 unordered_set 有关?
auto rng =
std::views::iota(0) |
std::views::transform([](size_t){ return rand() % 26; }) |
std::views::filter([u = std::unordered_set<size_t>()](size_t i) mutable { return !u.emplace(i).second; }) |
std::views::take(15);
for (auto&& x : rng) {
std::cout << x << std::endl;
}
Run Code Online (Sandbox Code Playgroud) 考虑以下预范围代码:
std::vector<int> v(1000*1000);
bool count_gt_5_v1(int val){
return std::count(v.begin(), v.end(), val)>5;
}
Run Code Online (Sandbox Code Playgroud)
它看起来比原始循环更好,但如果 val 在 v 中非常常见,它可能会非常低效。
有什么方法可以使用 C++20 范围,以便在我遇到 val 6 次后停止迭代。换句话说,我正在寻找一种在我的条件满足时引入休息的方法。我有这个可憎的东西,这似乎有效,但它比原始 for 循环丑得多。
bool count_gt_5_v2(int val){
int cnt=0;
auto span = std::ranges::views::take_while(v,[&cnt, &val]
(const auto elem)
{
cnt+=elem==val;
return cnt<6;
});
std::ranges::distance(span);
return cnt==6;
}
Run Code Online (Sandbox Code Playgroud)
完整代码链接:https : //godbolt.org/z/86djdK
该标准在[range.adaptors] 中定义了各种范围适配器,其中一些具有自己的迭代器类型。
为了标准化iterator_category这些迭代器,标准还规定了它们是如何定义的。例如,在[range.transform.iterator-2] 中,iterator_categoryoftransform_view?::?iterator定义如下:
成员typedef-name
iterator_category当且仅当Basemodels 定义forward_range。在那种情况下,iterator?::?iterator_category定义如下:让C表示类型iterator_traits<iterator_t<Base>>?::?iterator_category。如果
is_lvalue_reference_v<invoke_result_t<F&, range_reference_t<Base>>>是true,那么
如果
C模型derived_from<contiguous_iterator_tag>,iterator_category表示random_access_iterator_tag;否则,
iterator_category表示C。否则,
iterator_category表示input_iterator_tag。
但是这个定义似乎有一些问题,考虑以下情况:
vector v{1, 2, 3, 4, 5};
auto r = views::iota(0, 5) |
views::transform([&](int i) -> int& { return v[i]; });
using I = …Run Code Online (Sandbox Code Playgroud)