我偶然发现了与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 支持该示例,因此该示例应该可以工作。
首先,使用 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 上,这是示例。
我有两种点积实现:一种是手工编码的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。我认为在幕后范围只使用迭代器。这些表达式不等价吗?
我最近注意到以下代码不起作用:
#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] …
如何使用转换为自定义数据结构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 字符串 ( const char *),我想将其转换为 C++20 范围 (a forward_range) 以对其应用一些标准算法。
我不想使用,std::string_view因为我不想计算它的长度(字符串可以很长,我只关心前几个字符)。幸运的是,aforward_range不需要提前知道它的长度。
我该怎么做呢?我可以编写一个自定义迭代器,但希望有一种更简单的方法。
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 …
我曾经以一种可以用简单英语阅读的方式编写代码。
\n有人可以告诉我如何更好地用这些术语阅读下面的代码吗?
\n我的问题是,下面的代码读作 \xe2\x80\x9cerase all unique elements\xe2\x80\x9d ,而它的作用恰恰相反。
\n这并不是建议以某种方式重新设计 STL 和范围,我只是好奇std::unique在这种情况下考虑/处理(以及其他一些方法)的一些技巧,以使本文不那么违反直觉。
如果下面的代码中缺少 \xe2\x80\x9cnot\xe2\x80\x9d (这可能有助于读取为“不唯一”或“除了唯一”),那么阅读此代码的最佳方法是什么?
\nstd::vector<T> v = \xe2\x80\xa6;\nstd::sort(v.begin(), v.end());\nv.erase(std::unique(v.begin(), v.end()), v.end());\nRun Code Online (Sandbox Code Playgroud)\nRanges 版本在这些方面并没有更好:
\nstd::vector<T> v = \xe2\x80\xa6;\nstd::ranges::sort(v);\nv.erase(std::ranges::unique(v), v.end());\nRun Code Online (Sandbox Code Playgroud)\n #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