使用range-v3库(@EricNiebler),使编写算法代码更紧凑,例如,这里是如何生成一堆随机数:
#include <range/v3/all.hpp>
#include <iostream>
#include <vector>
int main()
{
using namespace ranges;
auto const N = 10;
std::vector<int> v;
v.reserve(N);
v |= action::push_back(view::iota(0, N));
random_shuffle(v);
copy(v, ostream_iterator<>(std::cout, ","));
}
Run Code Online (Sandbox Code Playgroud)
不过,我更愿意用一个假想延长了管道action::random_shuffle()这样
v |= action::push_back(view::iota(0, N)) | action::random_shuffle();
Run Code Online (Sandbox Code Playgroud)
这是我尝试编写这样的动作(不幸的是,编写新的range-v3代码比使用库更加冗长)
#include <functional> // bind, placeholders::_1
namespace ranges
{
inline namespace v3
{
/// \addtogroup group-actions
/// @{
namespace action
{
struct random_shuffle_fn
{
private:
friend action_access;
static auto bind(random_shuffle_fn random_shuffle)
RANGES_DECLTYPE_AUTO_RETURN
(
std::bind(random_shuffle, std::placeholders::_1)
)
template<typename Gen> …Run Code Online (Sandbox Code Playgroud) 我尝试了一个小例子来熟悉GSL和range-v3库,我想知道它们如何协同工作.我有这个玩具的例子
#include <iostream>
#include <range/v3/all.hpp>
using namespace std;
using namespace ranges;
void example_vector(vector<int> const& v)
{
ranges::for_each(view::tail(v), [](int x){
cout << x << ' ';
});
cout << '\n';
}
int main()
{
auto seq = vector<int> { 2,2,2,0,0,2,1,2 };
example_vector(seq);
}
Run Code Online (Sandbox Code Playgroud)
哪个有效.但是,如果我尝试使用gsl::span<int>范围,则会导致错误消息.编译器告诉我span没有满足视图概念.
#include <gsl.h>
// ...
void example_span(gsl::span<const int> v)
{
ranges::for_each(view::tail(v), [](int x){
cout << x << ' ';
});
cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)
编译器消息:
note: candidate template ignored: disabled by 'enable_if'
[with Rng …Run Code Online (Sandbox Code Playgroud) 似乎范围v3中的算法不可链接,即:
const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
const auto num_ones = ints | ranges::count(1);
Run Code Online (Sandbox Code Playgroud)
...必须写成功能风格:
const auto num_ones = ranges::count(ints, 1);
Run Code Online (Sandbox Code Playgroud)
这是一种设计选择,只有返回新范围/容器的算法/操作才是可管理的吗?
我尝试使用Ranges-V3库将一个值容器切割成一系列范围,使相邻范围共享边界元素.
考虑以下:
using namespace ranges;
std::vector<int> v = { 1, 2, 3, 0, 4, 0, 5, 0, 6, 7, 8, 0, 0, 9 };
auto myRanges = v | /* something like adjacent split */
for_each( myRanges, []( auto&& range ){ std::cout << range << std::endl;} );
Run Code Online (Sandbox Code Playgroud)
我想根据区域是否满足两个标准,将范围划分为重叠的子范围:
期望的输出:
[1,2,3]
[3,0,4,0,5,0,6]
[6,7,8]
[8,0,0,9]
Run Code Online (Sandbox Code Playgroud)
我的尝试:
auto degenerate =
[]( auto&& arg ){
return distance( arg ) < 2;
};
auto myRanges = v | view::split(0) | view::remove_if( degenerate ); …Run Code Online (Sandbox Code Playgroud) 假设我有一系列名为rng的T.我可以
auto groups = ranges::view::group_by(rng, bin_op);
Run Code Online (Sandbox Code Playgroud)
群体现在是T的范围.
我也可以这样做
auto groups = ranges::view::group_by(rng, bin_op) | ranges::to_vector;
Run Code Online (Sandbox Code Playgroud)
得到T的范围向量.不过这个
auto groups = ranges::view::group_by(rng, bin_op)
| ranges::to_vector
| ranges::action::transform([] (auto r) { return r | ranges::to_vector; };
Run Code Online (Sandbox Code Playgroud)
以及
auto groups = ranges::view::group_by(rng, bin_op)
| ranges::to_vector
| ranges::action::transform([] (auto r) { return std::vector<T>{} | ranges::action::push_back; };
Run Code Online (Sandbox Code Playgroud)
因为看起来range :: action :: transform()在这种情况下返回void并且"传递给action :: transform的函数的结果类型必须可写回源范围",因此不起作用.
那么如何将范围范围转换为矢量矢量?
注意:对不好的标签很抱歉,但我找不到范围/ range-ts/ranges-v3标签,我不允许创建一个标签,也不能在标题中使用它.
我需要std::string在所有空间拆分.但是,结果范围应该将其元素转换为std::string_views.我正在努力研究该系列的"元素类型".我想,类型就像是一个类似的东西c_str.如何将"分裂"部分转换为string_views?
#include <string>
#include <string_view>
#include "range/v3/all.hpp"
int main()
{
std::string s = "this should be split into string_views";
auto view = s
| ranges::view::split(' ')
| ranges::view::transform(std::string_view);
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个模板函数,它将汇总某些集合的所有元素 - 指定为普通的stl容器,或指定为range-v3的范围.(实际的功能,如下所示更通用)我认为这样可行:
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(range.begin());
Ret sum = zero;
int numElements = 0;
for (It it = range.begin(); it != range.end(); ++it) {
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
Run Code Online (Sandbox Code Playgroud)
这确实适用于STL元素,但不适用于范围.这给了我一个很长的错误:
<this file, at line 'using It'> error C2662: 'ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>>,ranges::v3::iter_transform_view<Rng,ranges::v3::indirected<Fun>>::adaptor<false>>>,ranges::v3::remove_if_view<ranges::v3::transform_view<Rng,Fun>,ranges::v3::logical_negate_<EnemyGroup::stepUpdate::<lambda_c582fb1297dce111c4572cef649d86b9>>>::adaptor>> ranges::v3::view_facade<Derived,ranges::v3::finite>::begin<Derived,false,0x0>(void)': cannot convert 'this' pointer from 'const Range' to 'ranges::v3::view_facade<Derived,ranges::v3::finite> &'
note: Conversion loses qualifiers
Run Code Online (Sandbox Code Playgroud)
最初,我认为这是范围-v3的vs2015分支的一些缺陷.没有多想,我只是快速解决了:
template …Run Code Online (Sandbox Code Playgroud) zip_withEric Niebler 提供了一个函数。
但是,既然 C++20 支持范围,我想构建类似的东西。
这个问题filter,并transform为他们迭代的范围?
我该怎么做呢?我已经坚持了一段时间,并且不愿意使用表达式模板。
例如,假设我有两个向量 M1{1,2,3} 和 M2{4,5,6}。
我想使用范围库来重载运算符以返回包含这两个矩阵相加的视图 - M1+M2 := {5,7,9}。
使用 range-v3,我可以执行 auto sum = zip_with(std::plus,M1,M2);
上面的表达式是惰性求值的。如何使用 C++20 范围重新创建此表达式?
C++20带来了更强大的迭代器系统,其中之一就是iterator_concept在iterator_category.
我发现C++20 中很多迭代器的iterator_concept和iterator_category是不一致的。以最著名iota_view的为例:
using R = decltype(views::iota(0));
static_assert(random_access_range<R>);
using I = ranges::iterator_t<R>;
static_assert(same_as<typename I::iterator_category, input_iterator_tag>);
static_assert(same_as<typename I::iterator_concept, random_access_iterator_tag>);
Run Code Online (Sandbox Code Playgroud)
虽然是Rmodels random_access_range,但iterator_category它的迭代器的the只是一个input_iterator_tag,与iterator_concept.
为什么C++20引入iterator_concept?它的目的是什么?如果我实现我自己的迭代器,我该如何界定iterator_concept和iterator_category正确?是否iterator_category仍然在C ++ 20的意思?
我有两个向量:
struct MyData{
double value;
};
std::vector<int> remove_flags = {0, 1, 0, 0, 0, 0, 1, 0};
std::vector<MyData> data = {{},{},{},{},{},{},{},{}};
Run Code Online (Sandbox Code Playgroud)
该remove_flags向量包含一个大小与 完全相同的标志数组data,每个标志要么是 0,要么是 1,其中 1 表示应删除数据。
我想用来remove_flags从data原地删除元素,即执行擦除删除习语,但根据remove_flags. 最终结果应该是data删除了元素,并希望删除remove_flags了那些相同的元素。
手动执行此操作很烦人,我想为此使用 Range-v3。我目前正在使用 C++17。
在查看文档后,我认为我没有找到解决方案,我能想到的最接近的事情是:
auto result = ranges::views::zip(remove_flags, data) | ranges::actions::remove_if([](std::pair<const int&, const MyData&> pair){
return pair.first != 0;
});
remove_flags.erase(result.first, remove_flags.end());
data.erase(result.second, data.end());
Run Code Online (Sandbox Code Playgroud)
但是操作无法对视图 zip 进行操作,因此无法编译。如果我切换ranges::actions::remove_if到ranges::views::remove_if一个奇怪的视图对象被返回,大概是一个没有实际std::remove对两个向量执行等效操作的对象。
我可以使用,contaner_to …
c++ ×10
range-v3 ×10
c++14 ×2
c++20 ×2
algorithm ×1
c++17 ×1
iterator ×1
std-ranges ×1
stl ×1
string ×1
string-view ×1
visual-c++ ×1