我想提供一个客户数据结构的视图,及其自己的迭代器。我写了一个小程序来测试它,如下所示。如果我取消注释 begin(),那么它就可以工作。但如果我使用 DummyIter,则会出现编译错误。
在我的完整程序中,我实现了一个完整的迭代器,但为了简单起见,我将其范围缩小到此处所需的功能。
#include <iostream>
#include <ranges>
#include <vector>
template<class T>
struct DummyIter
{
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
DummyIter() = default;
auto operator*() const { T t; return t; }
auto& operator++() { return *this; }
auto operator++(int val) { DummyIter tmp = *this; ++*this; return tmp; }
auto operator==(const DummyIter& iter) const { return true; }
};
template<class V>
struct DummyView : std::ranges::view_interface<DummyView<V>>
{
//auto begin() const { return std::ranges::begin(v); …Run Code Online (Sandbox Code Playgroud) 请注意,在提出此问题后,缺陷报告更改了下面提到的行为。见问题末尾。
考虑以下:
// Variant 1
template<auto> struct require_constexpr;
template<typename R>
constexpr auto is_constexpr_size(R&& r) {
return requires { typename require_constexpr<std::ranges::size(std::forward<R>(r))>; };
}
static_assert(!is_constexpr_size(std::vector{1,2,3,4}));
static_assert(is_constexpr_size(std::array{1,2,3,4}));
Run Code Online (Sandbox Code Playgroud)
这里的目标不是is_constexpr_size函数本身,而是找到一个 ( requires) 表达式,确定范围类型的大小是编译时常量,以便可以在按顺序通过转发引用获取任何范围的函数中使用它if constexpr基于它进行切换。
不幸的是,这不起作用,因为r它是引用类型并且不能在常量表达式中使用,尽管std::array调用std::range::sizes永远不会访问引用的对象。
变体 2:在函数参数中替换为 会改变这一点R&&。R非引用类型变量的常量表达式要求较弱,MSVC 和 GCC 都接受经过此更改的代码,但 Clang 仍然不接受。我的理解是,目前有一项更改规则的提案,以便 with 的变体R&&也能按预期工作。
然而,在实现这一点之前,我正在寻找一种替代方案,不需要将参数限制为非引用类型。我也不想依赖于范围的类型,例如默认可构造的类型。因此我无法构造正确类型的临时对象。std::declval也无法使用,因为std::ranges::size需要评估。
我尝试了以下方法:
// Variant 3
return requires (std::remove_reference_t<R> s) { typename require_constexpr<std::ranges::size(std::forward<R>(s))>; };
Run Code Online (Sandbox Code Playgroud)
这被 MSVC 接受,但不被 …
考虑这段代码:
#include <vector>
#include <iostream>
#include <cstdint>
#include <ranges>
int main()
{
struct S {
int a;
int b;
bool operator==(int other) const { return a == other; }
};
std::vector<S> iv{
{1, 2},
{3, 4}
};
// this works
if (auto const it{std::find(iv.begin(), iv.end(), 1)}; it != iv.end()) {
std::cout << "Found!\n" << "\n";
}
//std::ranges::find(iv, 2); // <-- why does this not compile
}
Run Code Online (Sandbox Code Playgroud)
我的印象是范围的调用约定将是相应原始算法的一对一映射(即,只需跳过 and .begin(),.end()它应该像以前一样工作)。
显然这里的情况并非如此。我缺少什么?
代码链接: https: //godbolt.org/z/3a6z9c5of
这个“管道”,存储库的主页说,不像范围的使用,即使它看起来一样:它不是基于懒惰的拉动,而是基于急切的推动。但是据说不能使用范围库来执行各种“管道”操作。例如:
我不太明白为什么原则上是这样。(当然,除了无法获得结束迭代器/哨兵的范围。)
考虑以下示例 ( Godbolt ):
#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>
struct A
{
A() {}
A( const A& ) { std::cout << "Copy\n"; }
A( A&& ) noexcept { std::cout << "Move\n"; }
A& operator=(const A&) { std::cout << "Copy assigned\n"; return *this; }
A& operator=( A&& ) noexcept { std::cout << "Move assigned\n"; return *this; }
int x = 10;
};
int main()
{
std::vector<A> vec( 10 );
std::cout << "Init\n";
std::cout << std::ranges::max( vec, [] ( …Run Code Online (Sandbox Code Playgroud) 我有一个打印整数列表的方法(我的实际方法有点复杂,但它也是只读的):
void printElements(const std::vector<int> &integersList)
{
std::for_each(integersList.begin(), integersList.end(), [](const auto& e){
std::cout << e << "\n";
});
}
Run Code Online (Sandbox Code Playgroud)
现在假设我有以下向量:
std::vector<int> vec{1,2,3,4,5,6,7,8,9,10};
Run Code Online (Sandbox Code Playgroud)
然后我只想打印偶数。为此,我考虑使用std::rangesC++20 中的新功能。我知道您可以按如下方式执行此操作:
auto evenList = vec | std::views::filter([](auto i){ return i % 2 == 0; });
Run Code Online (Sandbox Code Playgroud)
现在我想打电话printElements(evenList),但这显然不会编译。解决这个问题的办法是什么?我还可以编写一个函数来打印 astd::vector 和与我的类型相同的对象吗evenList?或者我需要编写两个单独的函数?
C++20(以及带有 的 23 std::ranges::to<T>())惯用地使用operator|来创建如下所示的转换管道:
return numbers
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * 2; })
| std::ranges::to<std::vector>();
Run Code Online (Sandbox Code Playgroud)
根据我的项目的当前情况.clang-format,看起来像
return numbers | std::views::filter([](int n) { return n % 2 == 0; }) |
std::views::transform([](int n) { return n * 2; }) | std::ranges::to<std::vector>();
Run Code Online (Sandbox Code Playgroud)
我觉得很难读。如果我设置BreakBeforeBinaryOperators: All我得到
return numbers | std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return …Run Code Online (Sandbox Code Playgroud) 我正在编写一个简单的 C++ 程序,它生成一个正态分布的随机整数值列表,然后获取前 N 个生成的项目并过滤它们,使它们的绝对值大于 42。我编写的代码如下:
int main() {
//convenience
namespace rng = std::ranges;
namespace view = std::views;
//random generation boilerplate
std::random_device r;
std::mt19937 gen(r());
std::normal_distribution<float> taps(-4, 15);
//the filtering
for (const auto& value : view::repeat(0)
| view::transform([&taps, &gen](auto _) { return std::round(taps(gen)); })
| view::take(1005)
| view::filter([](auto val) { return (val < -42 || val > 42); }))
{
std::cout << value << ' ';
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我删除该view::filter行,则序列似乎完全正常,并且大约有 3 个左右的值满足条件。然而,当应用过滤器时,输出似乎是一些随机垃圾,例如-12 -8 -14 2 -4 …
std::begin和 new 和有什么不一样std::ranges::begin?(同样为end,size等等)
两者似乎工作相同:
#include <iostream>
#include <vector>
#include <array>
#include <ranges>
template<std::ranges::range R>
void printInfo(const R &range)
{
std::cout << (std::ranges::begin(range) == std::begin(range));
}
template<class T>
struct X
{
std::vector<T> v;
auto begin() const { return v.begin(); }
auto end() const { return v.end(); }
};
int main()
{
printInfo(std::vector{1, 2, 3, 4});
printInfo(std::array{1, 2, 3, 4});
printInfo(X<int>{{1, 2, 3, 4}});
int oldSchool[]{1, 2, 3, 4};
printInfo(oldSchool);
}
Run Code Online (Sandbox Code Playgroud)
1111按预期编译和打印。
难道ranges::begin …
为什么这段代码可以在#if 0块就位的情况下工作,但如果删除它,则会失败并显示一组相当复杂的错误消息?更重要的是,我如何使它与上面非常相似的块得到相同的结果?
#include <ranges>
#include <iterator>
#include <optional>
#include <string_view>
#include <iostream>
#include <algorithm>
template <::std::ranges::view View,
typename Pred>
requires ::std::ranges::input_range<View> &&
::std::ranges::common_range<View> &&
::std::is_object_v<Pred> &&
::std::indirect_unary_predicate<const Pred, ::std::ranges::iterator_t<View>>
class skip_after_view : public ::std::ranges::view_interface<skip_after_view<View, Pred>>
{
public:
skip_after_view() = default;
skip_after_view(View v, Pred p)
: subview_(::std::move(v)), pred_(::std::move(p))
{}
class iterator;
friend class iterator;
auto begin() const {
return iterator{subview_.begin(), subview_.end(), &pred_};
}
auto end() const {
return iterator{subview_.end(), subview_.end(), &pred_};
}
private:
View subview_ = View();
Pred pred_; …Run Code Online (Sandbox Code Playgroud) c++ ×10
std-ranges ×10
c++20 ×8
g++ ×2
c++-concepts ×1
c++14 ×1
clang ×1
clang-format ×1
filter ×1
gcc ×1
libstdc++ ×1
range ×1
range-v3 ×1
stl ×1