考虑以下情况:
std::vector<int> v{0, 1, 2, 3, 4, 5};
// 0 1 2 3 4 5
auto rng1 = std::views::all(v);
// 5 4 3 2 1 0
auto rng2 = std::views::reverse(v);
// 4 2 0
auto rng3 = std::views::filter(rng2, [](int x){return x % 2 == 0;});
Run Code Online (Sandbox Code Playgroud)
有没有一种优雅的方法将这三个适配器连接到一个视图中,如下所示:
// 0 1 2 3 4 5 5 4 3 2 1 0 4 2 0
auto final_rng = std::views::concat(rng1, rng2, rng3);
Run Code Online (Sandbox Code Playgroud)
这似乎不可能,因为rng1、rng2、 和rng3是非常不同的类型。
有人可以提供替代解决方案吗?谢谢。
我想创建一个deep_flatten函数模板,它会产生一个range深度join编辑的元素。例如,如果我们只考虑嵌套的std::vectors,我可以有:
template <typename T>
struct is_vector : public std::false_type { };
template <typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type { };
template <typename T>
auto deepFlatten(const std::vector<std::vector<T>>& vec) {
using namespace std::ranges;
if constexpr (is_vector<T>::value) {
auto range = vec | views::join;
return deepFlatten(std::vector(range.begin(), range.end()));
} else {
auto range = vec | views::join;
return std::vector(range.begin(), range.end());
}
}
Run Code Online (Sandbox Code Playgroud)
这使我能够做到:
std::vector<std::vector<std::vector<int>>> nested_vectors = {
{{1, 2, 3}, {4, 5}, …Run Code Online (Sandbox Code Playgroud) 为什么std::range::sort(和其他基于范围的算法)在range命名空间中实现?为什么不将其定义为std::sort范围超载?
下面的代码不能在 Visual Studio 中编译,给出
错误 C2672 'operator __surrogate_func':未找到匹配的重载函数 sortms C:\Users\David\source\repos\sortms\sortms.cpp 103
当我使用 C 风格数组时,该函数按照编写的方式工作。如果我使用指定的注释代码,该函数也可以工作input.begin(), input.end(), output.begin()。
我使用的是 Visual Studio Community 2019 v16.8.6,使用该/std:c++latest选项进行编译。我认为标准容器是基于范围的?
std::range::copy()有人可以帮助我更好地理解vsstd::copy()在处理向量或其他标准容器时的优势吗?
#include <iostream>
#include <ranges>
#include <algorithm>
#include <array>
#include <utility>
#include <vector>
#include <functional>
#include <string>
#include <concepts>
void ranges_copy_demo()
{
std::cout << "\nstd::ranges::copy()\n";
/*
int const input[] = { 1, 2, 3, 5, 8, 13, 21, 34, 45, 79 };
int output[10] = { 0 };
*/
std::vector<int> input …Run Code Online (Sandbox Code Playgroud) 我喜欢你可以使用惰性范围的想法std::views::iota,但惊讶地发现这iota是目前标准中唯一类似的东西;views::single它是除了和之外唯一的“范围工厂” views::empty。例如,目前还没有相当于std::generate炼油厂的工厂。
然而我注意到,通过在 iota 上使用变换视图来实现语义是微不足道的generate,并且忽略 iota 传递给变换的值,即
#include <iostream>
#include <ranges>
#include <random>
template<typename F>
auto generate1(const F& func) {
return std::views::iota(0) | std::views::transform([&func](int) {return func(); });
}
std::random_device dev;
std::mt19937 rng(dev());
int main() {
auto d6 = []() {
static std::uniform_int_distribution<> dist(1, 6);
return dist(rng);
};
for (int v : generate1(d6) | std::views::take(10)) {
std::cout << v << ' ';
}
std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)
我的问题是实施这样的事情的“真正方法”是什么?制作一个可通过管道传输的范围视图对象,而不仅仅是使用iota. …
在 C++23 中,范围(子)库已获得std::ranges::zip,它将多个范围压缩为单个范围std::tuple(或对)。这很好,并且不需要我们自己实现它,使用boost::zip_iterator或诉诸这种黑客*。
然而,我们也得到std::ranges::zip_transform. 为什么我们需要它?毕竟,我们可以将 a 应用于ranges::views::transform压缩范围,不是吗?那么,是不是zip_transform多余呢?
* - 该 hack 在 C++11 中运行良好,并且不需要数万行带有概念的代码......
考虑以下代码(单击此处获取 Godbolt):
#include <algorithm>
#include <ranges>
#include <vector>
int main() {
auto v = std::vector<short>{1, 2};
auto view = v | std::views::transform([] (auto i) { return static_cast<int>(i); });
auto it = view.begin() + 1;
auto prev_it = std::ranges::prev(it); //this one is fine
//auto prev_it = std::prev(it); //this one dies with an infinite loop
return *prev_it;
}
Run Code Online (Sandbox Code Playgroud)
主要问题:调用std::prev而不是调用std::ranges::prev迭代器会使 gcc 陷入无限循环。这意味着存在编译器错误或代码调用std::prev调用了未定义的行为——这是哪一个?
关于后者的一些想法:std::prev需要LegacyBidirectionalIterator,而std::ranges::prev需要概念bidirectional_iterator。从我的理解,这两者之间的唯一区别是(从说明采取bidirectional_iterator): …
boost::join在混合 的输出时,我遇到了意外的行为std::views::transform(如下所示)。编译器不会发出任何警告。幸运的是,地址清理程序可以检测到get2b().
该get1b()函数遵循与 相同的模式get2b(),但该代码工作正常。考虑到 UB 的可能性,我如何确定构造的范围是合法的?我偏执的一面想get1b()写成return std::move(rng) | ...。
https://www.godbolt.org/z/Y77YW3jYb
#include <array>
#include <ranges>
#include <algorithm>
#include <iostream>
#include <iterator>
#include "boost/range/join.hpp"
#include "boost/range/adaptor/transformed.hpp"
inline auto square = [](int x) { return x*x; };
struct A {
std::array<std::vector<int>, 3> m_data{ std::vector{1, 2}, std::vector{3, 4, 5}, std::vector{6} };
auto join1() const { return m_data | std::views::join; }
auto join2() const { return boost::join(m_data[0], boost::join(m_data[1], m_data[2])); }
auto get1a() …Run Code Online (Sandbox Code Playgroud) 有一个相当典型的任务是同时对两个数组进行排序,假设数组的相同索引元素形成虚拟对,并对其进行排序。这样的问题至少在 10 年前就出现过:boost zip_iterator 和 std::sort
现在这个任务可以使用range-v3库来解决:
#include <array>
#include <range/v3/all.hpp>
int main() {
auto x = std::array{ 3, 2, 4, 1 };
auto y = std::array{'A', 'B', 'C', 'D'};
ranges::sort( ranges::views::zip( x, y ) );
// here x = {1,2,3,4}, y={'D','B','A','C'}
}
Run Code Online (Sandbox Code Playgroud)
在线演示: https: //gcc.godbolt.org/z/WGo4vGsx5
在 C++23 中出现了std::ranges::zip_view,我的期望是可以仅使用标准库编写相同的程序:
#include <array>
#include <ranges>
#include <algorithm>
int main() {
auto x = std::array{ 3, 2, 4, 1 };
auto y = std::array{'A', 'B', 'C', 'D'};
std::ranges::sort( std::views::zip( …Run Code Online (Sandbox Code Playgroud)