标签: std-ranges

为什么 std::ranges::upper_bound 不接受异构比较?

此代码有效并从向量返回一个foo{5}迭代器:

struct foo {
    int value;
};

auto main() -> int {
    auto ints = std::vector<foo>{{3}, {2}, {5}, {6}, {7}, {0}, {4}, {6}};

    std::ranges::sort(ints, {}, &foo::value);
    auto it = std::upper_bound(
            ints.begin(), ints.end(),
            4,
            [](const int v, const foo f) {
                return v < f.value;
            }
    );
}
Run Code Online (Sandbox Code Playgroud)

然而,这不能编译:

struct foo {
    int value;
};

auto main() -> int {
    auto ints = std::vector<foo>{{3}, {2}, {5}, {6}, {7}, {0}, {4}, {6}};

    std::ranges::sort(ints, {}, &foo::value);
    auto it = std::ranges::upper_bound(     // …
Run Code Online (Sandbox Code Playgroud)

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

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

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
查看次数

为什么 C++23 Ranges::to 不将容器类型 C 限制为范围?

C++23 引入了非常强大的ranges::to从范围构造对象(通常是容器)的功能,具有以下定义([range.utility.conv.to]):

\n
template<class C, input_\xc2\xadrange R, class... Args> requires (!view<C>)\n  constexpr C to(R&& r, Args&&... args);\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,它仅限制模板参数C不是 a view,也就是说,C甚至可能不是 a range

\n

然而,它的实现用于range_value_t<C>获取 的元素类型C,这C至少使得模板参数必须对 a 进行建模的给range定约束。range_value_tRrange

\n

那么,为什么ranges::to对模板参数的约束如此宽松C

\n

我注意到论文的 R3 版本过去常常约束Cinput_range,这显然是合理的,因为input_range保证了 是range_value_t格式良好的,但在 R4 中这个约束被删除了。而且我没有找到任何关于此更改的评论。

\n

C那么,消除必须的约束有哪些考虑因素呢input_range

\n

有没有一个实际的例子来说明这种约束放松的好处?

\n

c++ range-v3 std-ranges c++23

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

可以避免范围最小重新计算吗

目标是在一定范围的输入值上最小化函数。性能很重要。不幸的是,该ranges::min()算法一遍又一遍地重新计算实时最优的输出。

看起来该算法可以缓存与最佳值相对应的输出值,或者我错过了什么?

在这个例子中,为什么f(x=0)需要调用n次呢?

#include <ranges>
#include <algorithm>
#include <stdio.h>
using namespace std;

int main()
{
    auto f=[](int x){
        printf("calling f(x=%d)\n", x);
        return x*x;
    };
    auto rg = views::iota(0,4);
    int x1 = ranges::min(rg, {}, f);
}
Run Code Online (Sandbox Code Playgroud)

它输出:

调用 f(x=0)
调用 f(x=1)
调用 f(x=0)
调用 f(x=2)
调用 f(x=0)
调用 f(x=3)

有没有ranges::min()更优化的调用方式?

c++ min minimization c++20 std-ranges

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

范围 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
查看次数