标签: std-ranges

在 C++20 中将多个范围适配器连接成一个范围

考虑以下情况:

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)

这似乎不可能,因为rng1rng2、 和rng3是非常不同的类型。

有人可以提供替代解决方案吗?谢谢。

c++ range-v3 c++20 std-ranges

8
推荐指数
1
解决办法
4690
查看次数

使用基于概念的递归函数模板在推导“auto”之前使用“auto [...]”

我想创建一个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)

c++ c++-concepts c++20 std-ranges

8
推荐指数
1
解决办法
531
查看次数

为什么 C++20 范围库有自己的命名空间?

为什么std::range::sort(和其他基于范围的算法)在range命名空间中实现?为什么不将其定义为std::sort范围超载?

c++ c++20 std-ranges

8
推荐指数
1
解决办法
262
查看次数

std::ranges::copy 在 Visual Studio 中不会接受 std::vector

下面的代码不能在 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)

c++ compiler-errors c++20 std-ranges

8
推荐指数
1
解决办法
2143
查看次数

如何为 C++20 范围实现一个只调用生成器函数的惰性“范围工厂”?

我喜欢你可以使用惰性范围的想法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++ c++20 std-ranges

8
推荐指数
1
解决办法
1374
查看次数

如果我们有ranges::zip和views::transform,为什么我们需要ranges::zip_transform?

在 C++23 中,范围(子)库已获得std::ranges::zip,它将多个范围压缩为单个范围std::tuple(或对)。这很好,并且不需要我们自己实现它,使用boost::zip_iterator或诉诸这种黑客*

然而,我们也得到std::ranges::zip_transform. 为什么我们需要它?毕竟,我们可以将 a 应用于ranges::views::transform压缩范围,不是吗?那么,是不是zip_transform多余呢?


* - 该 hack 在 C++11 中运行良好,并且不需要数万行带有概念的代码......

c++ idioms tuples std-ranges

8
推荐指数
1
解决办法
950
查看次数

为什么使用 std::ranges 算法而不是常规算法?

cppreference状态

范围库是算法和迭代器库的扩展和泛化,通过使它们可组合且不易出错,使它们变得更加强大。

该库创建并操作范围视图,即间接表示可迭代序列(范围)的轻量级对象。

它提到使用范围视图,如 cppreference所述

范围概念定义了类型的要求,该类型允许通过提供表示范围元素的迭代器和标记来迭代其元素。

但从外部角度来看,它似乎只是带有concept. 所以主要问题是:

  • 使用范围库解决的常规迭代器有哪些问题(我们将不胜感激代码示例),以及何时应该使用它?

c++ algorithm stl std-ranges

8
推荐指数
1
解决办法
858
查看次数

转换视图的 std::prev 上的未定义行为

考虑以下代码(单击此处获取 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): …

c++ undefined-behavior c++20 std-ranges

7
推荐指数
1
解决办法
112
查看次数

有没有办法确定范围是否正确构建?

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)

c++ boost c++20 std-ranges

7
推荐指数
1
解决办法
156
查看次数

使用 C++23 zip 视图对两个数组进行排序

有一个相当典型的任务是同时对两个数组进行排序,假设数组的相同索引元素形成虚拟对,并对其进行排序。这样的问题至少在 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)

c++ std-ranges c++23

7
推荐指数
1
解决办法
672
查看次数