标签: std-ranges

我的自定义 std::ranges 迭代器中缺少什么?

我想提供一个客户数据结构的视图,及其自己的迭代器。我写了一个小程序来测试它,如下所示。如果我取消注释 begin(),那么它就可以工作。但如果我使用 DummyIter,则会出现编译错误。

在我的完整程序中,我实现了一个完整的迭代器,但为了简单起见,我将其范围缩小到此处所需的功能。

#include <iostream>
#include <ranges>
#include <vector>

template<class T>
struct DummyIter
{
  using iterator_category = std::random_access_iterator_tag;
  using value_type = T;
  using difference_type = std::ptrdiff_t;

  DummyIter() = default;

  auto operator*() const { T t; return t; }

  auto& operator++() { return *this; }

  auto operator++(int val) { DummyIter tmp = *this; ++*this; return tmp; }

  auto operator==(const DummyIter& iter) const { return true; }
};

template<class V>
struct DummyView : std::ranges::view_interface<DummyView<V>>
{
  //auto begin() const { return std::ranges::begin(v); …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges

17
推荐指数
2
解决办法
1802
查看次数

检测范围大小的编译时常数

请注意,在提出此问题后,缺陷报告更改了下面提到的行为。见问题末尾。


编译器资源管理器链接

考虑以下:

// Variant 1

template<auto> struct require_constexpr;

template<typename R>
constexpr auto is_constexpr_size(R&& r) {
    return requires { typename require_constexpr<std::ranges::size(std::forward<R>(r))>; };
}

static_assert(!is_constexpr_size(std::vector{1,2,3,4}));
static_assert(is_constexpr_size(std::array{1,2,3,4}));
Run Code Online (Sandbox Code Playgroud)

这里的目标不是is_constexpr_size函数本身,而是找到一个 ( requires) 表达式,确定范围类型的大小是编译时常量,以便可以在按顺序通过转发引用获取任何范围的函数中使用它if constexpr基于它进行切换。

不幸的是,这不起作用,因为r它是引用类型并且不能在常量表达式中使用,尽管std::array调用std::range::sizes永远不会访问引用的对象。

变体 2:在函数参数中替换为 会改变这一点R&&R非引用类型变量的常量表达式要求较弱,MSVC 和 GCC 都接受经过此更改的代码,但 Clang 仍然不接受。我的理解是,目前有一项更改规则的提案,以便 with 的变体R&&也能按预期工作。

然而,在实现这一点之前,我正在寻找一种替代方案,不需要将参数限制为非引用类型。我也不想依赖于范围的类型,例如默认可构造的类型。因此我无法构造正确类型的临时对象。std::declval也无法使用,因为std::ranges::size需要评估。

我尝试了以下方法:

// Variant 3

return requires (std::remove_reference_t<R> s) { typename require_constexpr<std::ranges::size(std::forward<R>(s))>; };
Run Code Online (Sandbox Code Playgroud)

这被 MSVC 接受,但不被 …

c++ language-lawyer c++-concepts c++20 std-ranges

15
推荐指数
1
解决办法
903
查看次数

为什么 std::ranges::find 不能编译,而 std::find 工作正常?

考虑这段代码:

#include <vector>
#include <iostream>
#include <cstdint>
#include <ranges>

int main()
{
    struct S {
        int  a;
        int  b;
        bool operator==(int other) const { return a == other; }
    };
    std::vector<S> iv{
        {1, 2},
        {3, 4}
    };

    // this works
    if (auto const it{std::find(iv.begin(), iv.end(), 1)}; it != iv.end()) {
        std::cout << "Found!\n" << "\n";
    }

    //std::ranges::find(iv, 2); // <-- why does this not compile
    
}
Run Code Online (Sandbox Code Playgroud)

我的印象是范围的调用约定将是相应原始算法的一对一映射(即,只需跳过 and .begin().end()它应该像以前一样工作)。

显然这里的情况并非如此。我缺少什么?

代码链接: https: //godbolt.org/z/3a6z9c5of

c++ c++20 std-ranges

15
推荐指数
1
解决办法
1441
查看次数

为什么范围不能用于管道库功能?

乔纳森博卡拉(作者流利C ++)写了一个叫做库的管道

这个“管道”,存储库的主页说,不像范围的使用,即使它看起来一样:它不是基于懒惰的拉动,而是基于急切的推动。但是据说不能使用范围库来执行各种“管道”操作。例如:

  • unzip - 采用压缩输入 - 本质上是一系列 k 元组 - 并产生 k 个单独的、独立的输出。
  • fork - 生成容器/范围的多个(独立)副本。

我不太明白为什么原则上是这样。(当然,除了无法获得结束迭代器/哨兵的范围。)

c++ c++14 range-v3 std-ranges

14
推荐指数
1
解决办法
396
查看次数

为什么 GCC 为 `std::ranges::max` 中的每次比较复制对象?

考虑以下示例 ( Godbolt ):

#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>

struct A
{
    A() {}
    A( const A& ) { std::cout << "Copy\n"; }
    A( A&& ) noexcept { std::cout << "Move\n"; }

    A& operator=(const A&) { std::cout << "Copy assigned\n"; return *this; }
    A& operator=( A&& ) noexcept { std::cout << "Move assigned\n"; return *this; }

    int x = 10;
};

int main()
{
    std::vector<A> vec( 10 );
    std::cout << "Init\n";
    std::cout << std::ranges::max( vec, [] ( …
Run Code Online (Sandbox Code Playgroud)

c++ gcc stl clang std-ranges

14
推荐指数
1
解决办法
740
查看次数

在 C++20 中将 std::ranges::views 作为参数传递

我有一个打印整数列表的方法(我的实际方法有点复杂,但它也是只读的):

void printElements(const std::vector<int> &integersList)
{
    std::for_each(integersList.begin(), integersList.end(), [](const auto& e){
        std::cout << e << "\n";
    });
}
Run Code Online (Sandbox Code Playgroud)

现在假设我有以下向量:

std::vector<int> vec{1,2,3,4,5,6,7,8,9,10};
Run Code Online (Sandbox Code Playgroud)

然后我只想打印偶数。为此,我考虑使用std::rangesC++20 中的新功能。我知道您可以按如下方式执行此操作:

auto evenList = vec | std::views::filter([](auto i){ return i % 2 == 0; });
Run Code Online (Sandbox Code Playgroud)

现在我想打电话printElements(evenList),但这显然不会编译。解决这个问题的办法是什么?我还可以编写一个函数来打印 astd::vector 与我的类型相同的对象吗evenList?或者我需要编写两个单独的函数?

c++ c++20 std-ranges

13
推荐指数
1
解决办法
3163
查看次数

调整 C++20 范围管道的 clang-format

C++20(以及带有 的 23 std::ranges::to<T>())惯用地使用operator|来创建如下所示的转换管道:

    return numbers 
        | std::views::filter([](int n) { return n % 2 == 0; })
        | std::views::transform([](int n) { return n * 2; })
        | std::ranges::to<std::vector>();
Run Code Online (Sandbox Code Playgroud)

根据我的项目的当前情况.clang-format,看起来像

    return numbers | std::views::filter([](int n) { return n % 2 == 0; }) |
           std::views::transform([](int n) { return n * 2; }) | std::ranges::to<std::vector>();
Run Code Online (Sandbox Code Playgroud)

我觉得很难读。如果我设置BreakBeforeBinaryOperators: All我得到

    return numbers | std::views::filter([](int n) { return n % 2 == 0; })
           | std::views::transform([](int n) { return …
Run Code Online (Sandbox Code Playgroud)

c++ clang-format c++20 std-ranges

12
推荐指数
1
解决办法
900
查看次数

C++20 的 std::views::filter 未正确过滤视图

我正在编写一个简单的 C++ 程序,它生成一个正态分布的随机整数值列表,然后获取前 N 个生成的项目并过滤它们,使它们的绝对值大于 42。我编写的代码如下:

int main() {
//convenience
    namespace rng = std::ranges;
    namespace view = std::views;
//random generation boilerplate
    std::random_device r;
    std::mt19937 gen(r());
    std::normal_distribution<float> taps(-4, 15);
 //the filtering   
    for (const auto& value : view::repeat(0)
        | view::transform([&taps, &gen](auto _) { return std::round(taps(gen)); })
        | view::take(1005)
        | view::filter([](auto val) { return (val < -42 || val > 42); }))
    {
        std::cout << value << ' ';
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我删除该view::filter行,则序列似乎完全正常,并且大约有 3 个左右的值满足条件。然而,当应用过滤器时,输出似乎是一些随机垃圾,例如-12 -8 -14 2 -4 …

c++ g++ filter c++20 std-ranges

12
推荐指数
2
解决办法
1630
查看次数

std::ranges::begin 和 std::begin 有什么区别?

std::begin和 new 和有什么不一样std::ranges::begin?(同样为endsize等等)

两者似乎工作相同:

#include <iostream>
#include <vector>
#include <array>
#include <ranges>

template<std::ranges::range R>
void printInfo(const R &range)
{
    std::cout << (std::ranges::begin(range) == std::begin(range));
}

template<class T>
struct X
{
    std::vector<T> v;

    auto begin() const { return v.begin(); }
    auto end() const { return v.end(); }
};

int main()
{
    printInfo(std::vector{1, 2, 3, 4});
    printInfo(std::array{1, 2, 3, 4});
    printInfo(X<int>{{1, 2, 3, 4}});

    int oldSchool[]{1, 2, 3, 4};
    printInfo(oldSchool);
}
Run Code Online (Sandbox Code Playgroud)

1111按预期编译和打印。

难道ranges::begin …

c++ range c++20 std-ranges

11
推荐指数
1
解决办法
610
查看次数

您如何使用运算符 | 创建与现有视图交互的自己的视图?

为什么这段代码可以在#if 0块就位的情况下工作,但如果删除它,则会失败并显示一组相当复杂的错误消息?更重要的是,我如何使它与上面非常相似的块得到相同的结果?

#include <ranges>
#include <iterator>
#include <optional>
#include <string_view>
#include <iostream>
#include <algorithm>

template <::std::ranges::view View,
          typename Pred>
requires ::std::ranges::input_range<View> &&
         ::std::ranges::common_range<View> &&
         ::std::is_object_v<Pred> &&
         ::std::indirect_unary_predicate<const Pred, ::std::ranges::iterator_t<View>>
class skip_after_view : public ::std::ranges::view_interface<skip_after_view<View, Pred>>
{
 public:
   skip_after_view() = default;
   skip_after_view(View v, Pred p)
        : subview_(::std::move(v)), pred_(::std::move(p))
   {}
   class iterator;
   friend class iterator;

   auto begin() const {
       return iterator{subview_.begin(), subview_.end(), &pred_};
   }
   auto end() const {
       return iterator{subview_.end(), subview_.end(), &pred_};
   }

 private:
   View subview_ = View();
   Pred pred_; …
Run Code Online (Sandbox Code Playgroud)

c++ g++ libstdc++ c++20 std-ranges

11
推荐指数
1
解决办法
275
查看次数