gpt4 book ai didi

C++20 流又名范围

转载 作者:行者123 更新时间:2023-12-03 20:23:24 25 4
gpt4 key购买 nike

当我使用 Stream Library ( http://jscheiny.github.io/Streams/api.html# ) 时,我可以像在 Java-Streams 中那样做类似的事情:

#include "Streams/source/Stream.h"
#include <iostream>

using namespace std;
using namespace stream;
using namespace stream::op;

int main() {

list<string> einkaufsliste = {
"Bier", "Käse", "Wurst", "Salami", "Senf", "Sauerkraut"
};

int c = MakeStream::from(einkaufsliste)
| filter([] (string s) { return !s.substr(0,1).compare("S"); })
| peek([] (string s) { cout << s << endl; })
| count()
;

cout << c << endl;
}

它给出了这个输出:
Salami
Senf
Sauerkraut
3
在 C++20 中,我发现了范围,它看起来很有希望实现同样的目标。但是,当我想构建类似的函数式编程风格时,它不起作用:
#include <iostream>
#include <ranges>
#include <vector>
#include <algorithm>

using namespace std;

int main() {

vector<string> einkaufsliste = {
"Bier", "Käse", "Wurst", "Salami", "Senf", "Sauerkraut"
};

int c = einkaufsliste
| ranges::views::filter([] (string s) { return !s.substr(0,1).compare("S"); })
| ranges::for_each([] (string s) { cout << s << " "; })
| ranges::count();
;
}
尽管像这样的文章( https://www.modernescpp.com/index.php/c-20-the-ranges-library )暗示了这样的功能,但接缝并不意味着像这样工作。
test.cpp:16:67: note:   candidate expects 3 arguments, 1 provided
16 | | ranges::for_each([] (string s) { cout << s << " "; })
| ^
test.cpp:17:29: error: no match for call to '(const std::ranges::__count_fn) ()'
17 | | ranges::count();
| ^
任何想法如何我仍然可以在 C++20 中做类似的事情?

最佳答案

这里的每个适配器都有问题。

一、filter :

| ranges::views::filter([] (string s) { return !s.substr(0,1).compare("S"); })
这会复制每个字符串,然后从每个字符串中创建一个新字符串,只是为了检查第一个字符是否是 S .您绝对应该通过 const& 取字符串这里。然后,由于问题被标记为 C++20:
| ranges::views::filter([](string const& s) { return !s.starts_with('S'); })

二、 for_each :
| ranges::for_each([] (string s) { cout << s << " "; })
ranges::for_each不是范围适配器——它是一种算法,它在每个元素上调用可调用对象,但它不返回新范围,因此它不能适应这样的管道。
范围没有 peek像这样的适配器(既不是 C++20 也不是 range-v3)但是我们可以尝试用 transform 来实现它使用身份:
auto peek = [](auto f){
return ranges::views::transform([=]<typename T>(T&& e) -> T&& {
f(e);
return std::forward<T>(e);
});
};
现在你可以写(同样,这里的字符串应该被视为 const&):
| peek([](std::string const& s){ cout << s << " "; })
但这实际上只有在我们访问范围内的任何元素时才有效,并且您的代码中没有任何内容必须这样做(我们不需要读取任何元素来找到距离,我们只需要推进迭代器根据需要多次)。所以你会发现上面的内容实际上并没有打印任何东西。
所以相反, for_each是正确的方法,我们只需要分开做:
auto f = einkaufsliste
| ranges::views::filter([](string const& s) { return s.starts_with('S'); });
ranges::for_each(f, [](string const& s){ cout << s << " "; });
那肯定会打印每个元素。

最后, count :
| ranges::count();
在 Ranges 中,只有返回 View 的适配器是可管道化的。 count()只是不能这样工作。另外, count()需要第二个参数,即您正在计算的东西。 count(r, value)统计 value的实例数在 r .没有一元 count(r) .
您正在寻找的算法名为 distance (同样,不能通过管道导入)。
所以你必须像这样写整个事情:
int c = ranges::distance(f);
这是 P2011 的部分动机, 才能真正写出 count最后以线性顺序而不是在前面(无需进行更多的库更改)。

关于C++20 流又名范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66297660/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com