标签: std-ranges

为什么编译器无法自动匹配范围基 for 循环中“size_t”变量的类型?

我偶然发现了与range一起operator<<使用时存在不明确重载的问题。\n更具体地说,使用以下代码:std::views::enumeratesize_t

\n
#include <iostream>\n#include <ranges>\nnamespace rv = std::ranges::views;\n\nint main()\n{\n    for (const auto& [idx, value] : rv::iota(0zu, 5zu) | rv::enumerate)\n        std::cout << idx << '\\n';\n}\n
Run Code Online (Sandbox Code Playgroud)\n

gcc 13.1.1在 Linux 上使用以下命令进行编译:g++ --std=c++23 main.cpp.\n我收到错误:

\n
main.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\nmain.cpp:11:19: error: ambiguous overload for \xe2\x80\x98operator<<\xe2\x80\x99 (operand types are \xe2\x80\x98std::ostream\xe2\x80\x99 {aka \xe2\x80\x98std::basic_ostream<char>\xe2\x80\x99} and \xe2\x80\x98std::tuple_element<0, const std::tuple<__int128, long unsigned int> >::type\xe2\x80\x99 {aka \xe2\x80\x98const __int128\xe2\x80\x99})\n   11 |         std::cout << idx << '\\n';\n      |         ~~~~~~~~~ ^~ ~\n      |              | …
Run Code Online (Sandbox Code Playgroud)

c++ implicit-conversion std-ranges c++23

5
推荐指数
1
解决办法
220
查看次数

MSVC 上的“std::views::split”

我想用 和 的标记分割字符串std::views::split,并为每个检索到的子字符串调用该std::from_chars函数。这是一个 MRE ( https://godbolt.org/z/1K71qo9s4 ),它在 GCC 上编译成功,但在 MSVC 上编译失败:

#include <iostream>
#include <ranges>
#include <string>
#include <charconv>
 
 
int main()
{
    std::string source{"10%15%20%35"};
    for ( auto i : source | std::views::split('%') )
    {
        int x;
        std::from_chars( i.begin().base(), i.end().base(), x );
        std::cout << x << ' ';
    }
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,根据cppreference , P2210R2中的行为std::views::split发生了变化,提供了效果为base()

相当于return cur_

然后,根据编译器支持页面P2210R2自 19.31 起 MSVC 支持该示例,因此该示例应该可以工作。

c++ stl compiler-specific c++20 std-ranges

5
推荐指数
1
解决办法
217
查看次数

std::ranges::views::enumerate 在 GCC 上建立索引时是否使用了错误的类型?

首先,使用 Range-v3,我注意到

std::vector<int> v;
auto w = v | ranges::views::enumerate;
auto [x, y] = *w.begin();
static_assert(std::is_same_v<std::size_t, decltype(x)>);
Run Code Online (Sandbox Code Playgroud)

这对我来说很有意义,因为std::size_t据我所知,这是用于索引对象的正确类型

然后,对于 C++20 范围,静态断言会失败。相反,以下传递,

static_assert(std::is_same_v<long, decltype(x)>);
Run Code Online (Sandbox Code Playgroud)

但与我的系统上long的不一样,我在其中验证了这一点std::size_t

static_assert(std::is_same_v<unsigned long, std::size_t>)
Run Code Online (Sandbox Code Playgroud)

在 GCC 13.2.1 上,这是示例

c++ size-t language-lawyer std-ranges c++23

5
推荐指数
1
解决办法
209
查看次数

为什么编译器不在我的范围表达式中使用 SIMD?

我有两种点积实现:一种是手工编码的https://godbolt.org/z/48EEnnY4r

int bla2(const std::vector<int>& a, const std::vector<int>& b){

    int res = 0;
    for(size_t i=0; i < a.size(); ++i){
        res += a[i]*b[i];
    }
    return res;
}
Run Code Online (Sandbox Code Playgroud)

一个使用 C++23 的std::views::zip https://godbolt.org/z/TsGW1WYnf

int bla(const std::vector<int>& a, const std::vector<int>& b){

    int res = 0;
    for(const auto& [x,y]  : std::views::zip(a,b)){
        res += x*y;
    }
    return res;
}
Run Code Online (Sandbox Code Playgroud)

在 godbolt 中,手工编码版本使用了大量 SIMD 指令,而基于 zip 的实现则没有。这里发生了什么?如果我使用迭代器实现它,它也会获得 SIMD。我认为在幕后范围只使用迭代器。这些表达式不等价吗?

c++ gcc simd auto-vectorization std-ranges

5
推荐指数
0
解决办法
162
查看次数

为什么“ranges::min/max/minmax”要求迭代器满足“indirectly_copyable_storable”?

我最近注意到以下代码不起作用

#include <ranges>
#include <algorithm>
#include <memory>
#include <iostream>

int main() {
  std::cout << *std::ranges::max(
    std::views::iota(0, 5) |
    std::views::transform([](int i) { return std::make_unique<int>(i); }),
    {},
    std::ranges::iter_move // another spelling of '[](auto&& p) { return *p; }'
  );
}
Run Code Online (Sandbox Code Playgroud)

原因是ranges::max(同样适用rangs::min/minmax)的签名需要indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>

template<input_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  constexpr range_value_t<R>
    ranges::max(R&& r, Comp comp = {}, Proj proj = {});
Run Code Online (Sandbox Code Playgroud)

indirectly_copyable_storable是一个不太为人所知的概念,用于检查value_type迭代器的 是否可以临时存储和重新分配([alg.req.ind.copy] …

c++ c++20 std-ranges

5
推荐指数
0
解决办法
179
查看次数

如何为 std::ranges::to 启用我的类型?

如何使用转换为自定义数据结构std::ranges::to

基本上是这样的

struct my_data {
   char b;
   int foo;
   std::string baz;
};

auto text = "v 3 fool|x 56 description|e 123 name"sv;

auto converted = text | std::views::split('|') 
               | std::views::transform([](auto r) { 
                   return r | std::ranges::to<my_data>();
               }) | std::ranges::to<std::vector>();
// converted should be a vector<my_data>
Run Code Online (Sandbox Code Playgroud)

需要什么样的东西my_data才能使用它进行转换std::ranges::to

c++ std-ranges c++23

5
推荐指数
1
解决办法
197
查看次数

如何从 C 字符串获取 C++20forward_range 而不计算其长度?

我有一个 C 字符串 ( const char *),我想将其转换为 C++20 范围 (a forward_range) 以对其应用一些标准算法。

我不想使用,std::string_view因为我不想计算它的长度(字符串可以很长,我只关心前几个字符)。幸运的是,aforward_range不需要提前知道它的长度。

我该怎么做呢?我可以编写一个自定义迭代器,但希望有一种更简单的方法。

c++ std-ranges

5
推荐指数
1
解决办法
147
查看次数

是否有与 std::forward 等效的移动或复制功能,可以在 std::ranges 中完美转发?

How can I combine the following two functions into one? Is there something similar to std::forward, but for ranges?

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

template<class RangeIn, class RangeOut>
void moveOrCopy(RangeIn& from, RangeOut& to)
{
    std::ranges::copy(from, std::back_inserter(to));
}

template<class RangeIn, class RangeOut>
    requires std::is_rvalue_reference_v<RangeIn&&>
void moveOrCopy(RangeIn&& from, RangeOut& to)
{
    std::ranges::move(from, std::back_inserter(to));
}

void test()
{
  std::vector<int> a, b;
  moveOrCopy(a, b); // copy
  moveOrCopy(std::move(a), b); // move
}
Run Code Online (Sandbox Code Playgroud)

There is std::ranges::forward_range, but that's related to forward_iterator, not …

c++ perfect-forwarding c++20 std-ranges

5
推荐指数
3
解决办法
237
查看次数

C++ 标准库算法的可读性

我曾经以一种可以用简单英语阅读的方式编写代码。

\n

有人可以告诉我如何更好地用这些术语阅读下面的代码吗?

\n

我的问题是,下面的代码读作 \xe2\x80\x9cerase all unique elements\xe2\x80\x9d ,而它的作用恰恰相反。

\n

这并不是建议以某种方式重新设计 STL 和范围,我只是好奇std::unique在这种情况下考虑/处理(以及其他一些方法)的一些技巧,以使本文不那么违反直觉。

\n

如果下面的代码中缺少 \xe2\x80\x9cnot\xe2\x80\x9d (这可能有助于读取为“不唯一”或“除了唯一”),那么阅读此代码的最佳方法是什么?

\n
std::vector<T> v = \xe2\x80\xa6;\nstd::sort(v.begin(), v.end());\nv.erase(std::unique(v.begin(), v.end()), v.end());\n
Run Code Online (Sandbox Code Playgroud)\n

Ranges 版本在这些方面并没有更好:

\n
std::vector<T> v = \xe2\x80\xa6;\nstd::ranges::sort(v);\nv.erase(std::ranges::unique(v), v.end());\n
Run Code Online (Sandbox Code Playgroud)\n

c++ std-ranges

5
推荐指数
1
解决办法
335
查看次数

C++20 中引入的 std::views::all 是什么?

#include <vector>
#include <ranges>

int main()
{
    auto v = std::vector{1, 2, 3, 4};
    v | std::views::drop(2); // ok
    std::views::all(v) | std::views::drop(2); // also ok
}
Run Code Online (Sandbox Code Playgroud)

成功编译g++11 -std=c++20。但我无法分辨v | std::views::drop(2)和之间的任何区别std::views::all(v) | std::views::drop(2)

所以,我的问题是:

C++20 中引入了什么std::views::all

c++ standards c++-standard-library c++20 std-ranges

4
推荐指数
1
解决办法
373
查看次数