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()这种内在的view是inner-iterator和default_sentinel_t …
这里写的是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:它只返回一个整数,不一定是无符号的!
请参阅此示例代码:
#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 不用于实现此视图 - 那么这个实现是如何工作的?
我使用 SG14flat_map作为容器。
根据标准地图,它采用Key模板Value参数。
然而,与标准映射不同,它不存储std::pair<Key, Value>在二叉搜索树中,而是将键和值存储在两个单独的容器中(附加模板参数默认为std::vector)
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\nRun Code Online (Sandbox Code Playgroud)\n然后它定义了许多类型,如下所示:
\nusing 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>;\nRun Code Online (Sandbox Code Playgroud)\nstd::ranges::find_if如果我尝试在 上使用flat_map,则会收到错误: …
如果我创建一个视图,那么它就是一个范围。这似乎很合理。
\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}\nRun Code Online (Sandbox Code Playgroud)\n这是令人惊讶的 - 我看不出有任何理由我不应该能够阅读内容,就像我可以从const std::vector.
如果这是一个实现错误,我在 GCC 11 中遇到过这种情况,使用-std=c++20; 库是 libstdc++-11。
如果我添加一个调用,std::ranges::begin()我会得到大量诊断信息,显示它没有找到成员函数,也没有通过 ADL 找到任何内容,然后遇到了阻止std::begin匹配的后备删除函数。
从错误消息来看,我们似乎缺少视图类中的const 版本begin()和成员函数。end()这是预期的结果,还是只是被错过了?
这让我想到了一个更简单的失败示例:
\n#include <ranges>\n\nint main()\n{\n int values[] = …Run Code Online (Sandbox Code Playgroud) 我想使用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) 最初的问题是为什么使用以下代码,
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)
经过一些研究并研究潜在的重复项后,我了解到这是 …
什么时候
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) 我偶然发现了与range一起operator<<使用时存在不明确重载的问题。\n更具体地说,使用以下代码:std::views::enumeratesize_t
#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}\nRun Code Online (Sandbox Code Playgroud)\n并gcc 13.1.1在 Linux 上使用以下命令进行编译:g++ --std=c++23 main.cpp.\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) 我想用 和 的标记分割字符串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 支持该示例,因此该示例应该可以工作。