标签: std-ranges

什么情况下ranges::split_view的迭代器不满足copyable?

C++20 引入了 a ranges::split_view,它接受 aview和一个定界符,并view根据定界符将 a分成子范围。

分隔符也是 a view,当它是单个元素时,它会被包裹在 a 中ranges::single_view

每个返回的子范围也是一个view,它的类型是split_view::outer-iterator::value_type,在[range.adaptors#range.split.outer.value] 中定义:

template<bool Const>
struct split_view<V, Pattern>::outer-iterator<Const>::value_type
  : view_interface<value_type> {
private:
  outer-iterator i_ = outer-iterator();               // exposition only
public:
  value_type() = default;
  constexpr explicit value_type(outer-iterator i) : i_(std?::?move(i)) {}

  constexpr inner-iterator<Const> begin() const requires copyable<outer-iterator>
  constexpr inner-iterator<Const> begin() requires (!copyable<outer-iterator>);
  constexpr default_sentinel_t end() const;
};
Run Code Online (Sandbox Code Playgroud)

的返回类型begin()end()这种内在的viewinner-iteratordefault_sentinel_t …

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

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

std::ranges::size 是否应该返回无符号整数?

这里写的是std::ranges::size应该返回一个无符号整数。但是,当我在Eigen向量(使用 Eigen 3.4)上使用它时,将进行以下编译:

Eigen::VectorXd x;
static_assert(std::same_as<Eigen::VectorXd::Index,
                           decltype(std::ranges::size(x))>);
Run Code Online (Sandbox Code Playgroud)

其中Eigen::VectorXd::Index是众所周知的有符号整数。通过查看 的实现std::ranges::size,我注意到返回类型是从 的返回类型推断出来的x.size(),这正是Eigen::VectorXd::Index. 这是一个错误吗std::ranges::size?或者这是预期的?


更新 27/12/2021

上面链接的 C++ 参考页最终更改了该函数的描述std::ranges::size:它只返回一个整数,不一定是无符号的!

c++ eigen eigen3 c++20 std-ranges

5
推荐指数
2
解决办法
302
查看次数

这是正确的:无限范围内的 std::views::reverse 吗?

请参阅此示例代码

#include <ranges>

int main() {
    for(auto i : std::ranges::iota_view(1) | std::views::reverse) 
        break;
}
Run Code Online (Sandbox Code Playgroud)

它在 gcc 上编译(我无法检查 clang/msvc - 因为它们不支持范围)。当然——它“永远”运行并且什么也不做。

我还检查了不允许在无限范围内执行std::ranges::rbegin(inf)或操作std::ranges::rend(inf)(它无法编译)。

我不确定这是否是正确的 C++ 代码?我对 std::ranges::reverse 实现很好奇 - 看起来 rbegin/rend 不用于实现此视图 - 那么这个实现是如何工作的?

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

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

std::ranges::find_if - std::common_reference 中没有类型

我使用 SG14flat_map作为容器。

\n

根据标准地图,它采用Key模板Value参数。

\n

然而,与标准映射不同,它不存储std::pair<Key, Value>在二叉搜索树中,而是将键和值存储在两个单独的容器中(附加模板参数默认为std::vector

\n
template<\n    class Key,\n    class Mapped,\n    class Compare = std::less<Key>,\n    class KeyContainer = std::vector<Key>,\n    class MappedContainer = std::vector<Mapped>\n>\nclass flat_map\n
Run Code Online (Sandbox Code Playgroud)\n

然后它定义了许多类型,如下所示:

\n
using key_type = Key;\nusing mapped_type = Mapped;\nusing value_type = std::pair<const Key, Mapped>;\nusing key_compare = Compare;\nusing const_key_reference = typename KeyContainer::const_reference;\nusing mapped_reference = typename MappedContainer::reference;\nusing const_mapped_reference = typename MappedContainer::const_reference;\nusing reference = std::pair<const_key_reference, mapped_reference>;\nusing const_reference = std::pair<const_key_reference, const_mapped_reference>;\n
Run Code Online (Sandbox Code Playgroud)\n

std::ranges::find_if如果我尝试在 上使用flat_map,则会收到错误: …

c++ c++20 std-ranges

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

为什么 const 视图不是范围?

如果我创建一个视图,那么它就是一个范围。这似乎很合理。

\n

但是,如果它是 const,那么它就变成非范围:

\n
#include <ranges>\n\nint main()\n{\n    int values[] = { 1, 2, 3 };\n\n    auto odd_values = values | std::views::filter([](int i){ return i % 2; });\n    static_assert(std::ranges::range<decltype(odd_values)>);\n\n    auto const odd_ref = odd_values;    \n    static_assert(!std::ranges::range<decltype(odd_ref)>); // WHY NOT?\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是令人惊讶的 - 我看不出有任何理由我不应该能够阅读内容,就像我可以从const std::vector.

\n

如果这是一个实现错误,我在 GCC 11 中遇到过这种情况,使用-std=c++20; 库是 libstdc++-11。

\n
\n

如果我添加一个调用,std::ranges::begin()我会得到大量诊断信息,显示它没有找到成员函数,也没有通过 ADL 找到任何内容,然后遇到了阻止std::begin匹配的后备删除函数。

\n

从错误消息来看,我们似乎缺少视图类中的const 版本begin()和成员函数。end()这是预期的结果,还是只是被错过了?

\n

这让我想到了一个更简单的失败示例:

\n
#include <ranges>\n\nint main()\n{\n    int values[] = …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges

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

使用 std::for_each 和 std::views::iota 的并行 for 循环

我想使用std::views.

为了按顺序运行,代码如下所示:

int main() {

    //pseudo-random numbers

    random_device rd;
    default_random_engine eng(rd());
    uniform_int_distribution<int> distr(0, 100);

    auto r = ranges::views::iota(0, 10);
    vector<double> v(10, 1);
    for_each(r.begin(), r.end(), [&](int i) {v[i] = distr(eng); });
    for (auto&& i : v) cout << i << " "; cout << endl;
}
Run Code Online (Sandbox Code Playgroud)

这很好用。我使用的是标准版本std::for_each(),而不是命名空间中的版本ranges,因为它们没有执行策略。现在是并行版本。唯一的区别:

for_each(execution::par, r.begin(), r.end(), [&](int i) {v[i] = distr(eng); });
Run Code Online (Sandbox Code Playgroud)

MSVC 报错:

error C2338: Parallel algorithms require forward iterators or stronger
Run Code Online (Sandbox Code Playgroud)

我在这里发现了类似的问题:Usingranges::view::iota inparallelalgorithm,我实现了那里提供的解决方案:

    auto r = views::iota(0) …
Run Code Online (Sandbox Code Playgroud)

c++ algorithm visual-c++ c++20 std-ranges

5
推荐指数
2
解决办法
1885
查看次数

范围 filter_view::iterator 元素修改导致 UB

最初的问题是为什么使用以下代码,

std::vector<int> coll{1,4,7,10};

auto iseven = [](auto&& i){return i % 2 == 0; };
auto  colleven = coll | std::views::filter(iseven);

// first view materialization
for(int& i : colleven)
{
    i += 1;
}
for(auto i : coll)
std::cout << i << ' ';
std::cout << std::endl;

// second view materialization
for(int& i : colleven)
{
    i += 1;
}
for(auto i : coll)
std::cout << i << ' ';
Run Code Online (Sandbox Code Playgroud)

通过两次具体化视图,我们得到两个不同的结果。乍一看这确实很奇怪。输出:

1 5 7 11 
1 6 7 11 
Run Code Online (Sandbox Code Playgroud)

经过一些研究并研究潜在的重复项后,我了解到这是 …

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

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

从变换切换到过滤器时,size() 会导致错误

什么时候

  • views::filter([](auto n) { return n % 2 == 0; });已激活,我无法获取[2,4]
  • views::transform([](auto n) { return 2 * n; });已激活,我成功获得了[2,4,6,8,10]
#include <iostream>
#include <ranges>
#include <sstream>

int main()
{
    using namespace std;
    auto input = views::iota(1, 5 + 1);

    auto output = input |
                  views::filter([](auto n) { return n % 2 == 0; });
                  //views::transform([](auto n) { return 2 * n; });


    stringstream ss;
    ss << "[";
    for (auto i = 0; i < output.size() …
Run Code Online (Sandbox Code Playgroud)

c++ std-ranges

5
推荐指数
2
解决办法
337
查看次数

为什么编译器无法自动匹配范围基 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
查看次数