标签: std-ranges

用户定义的容器不适用于 std::ranges

我无法让用户定义的容器与 std::ranges 一起使用。如果迭代器只是一个,我的容器就可以工作,int*但是一旦我创建了自己的迭代器类,就会出现编译器错误。

这有效。

#include <iostream>
#include <ranges>
using namespace std;

struct sentinel {};

class my_iota_view_a : public std::ranges::view_interface< my_iota_view_a >{
public:
    using value_type        = size_t;
    using iterator          = value_type *;

    my_iota_view_a() = default;
    my_iota_view_a( size_t begin ) : mBegin( &mData[begin] ) { }

    iterator begin() { return mBegin; }
    sentinel end() { return sentinel{}; }
private:
    value_type mData[10] ={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    value_type * mBegin;
};

bool operator==( my_iota_view_a::iterator …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges

2
推荐指数
1
解决办法
94
查看次数

为什么 std::ranges::view_interface 使用 CRTP

根据 cppreference,帮助类模板view_interface使用奇怪的重复模板模式 (CRTP) 技术定义视图。

它们背后的设计理念是什么?与覆盖派生类中的虚拟基类方法相比,是否有显着的优势?

c++ range-v3 c++20 std-ranges

2
推荐指数
1
解决办法
150
查看次数

错误:“排序”不是“std::ranges”的成员;您的意思是“std::sort”吗?

我运行了以下代码

vector<int> randomIntegers = generateIntegers(10); // Generates 10 integers

std::ranges::sort(randomIntegers);
Run Code Online (Sandbox Code Playgroud)

当我用 编译时g++ -std=c++20 file.cpp,我得到

error: 'sort' is not a member of 'std::ranges'; did you mean 'std::sort'?
Run Code Online (Sandbox Code Playgroud)
  • gcc --version:海湾合作委员会10.2.0
  • g++ --version:g++10.2.0

为什么 sort 不是成员?advance我正在使用 VScode intellisense,它显示了、begin、等方法common_view。但不排序。

c++ c++20 std-ranges g++10

2
推荐指数
1
解决办法
2029
查看次数

范围适配器对于可视范围背后的参数是否懒惰?

C++20 标准在[range.adaptors.general]中表示范围适配器

当迭代结果视图时延迟评估。

另一方面,在[range.filter.view]中,filter_view 的 begin 函数有一个注释,提到了缓存结果。那么适配器的懒惰程度如何呢?

当执行以下代码时:

#include <iostream>
#include <ranges>

void print(std::ranges::range auto&& r)
{
    for (const auto& item : r)
    {
        std::cout << item << ", ";
    }
    std::cout << " <end of range>\n";
}

int main()
{
    using namespace std::ranges;

    bool filter = false;
    
    auto v = iota_view{4, 10} | views::filter([&filter](auto item){return filter;});

    // multipass guarantee
    static_assert(std::ranges::forward_range<decltype(v)>);

    filter = true;
    print(v);

    filter = false;
    print(v);

    filter = true;
    print(v);
} …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges

2
推荐指数
1
解决办法
577
查看次数

Ranges::views 如何实现 O(1) 复杂度?

在最近介绍的 C++20 Ranges 中,我知道views通过使用视图适配器来实现可组合性。我也知道视图不拥有它们的元素,它们的性质是惰性的,也就是说它们只在需要时才进行实际计算。

视图如何实现O(1)移动、复制和分配操作的复杂性?那到我这里来的可能的答案是,意见是刚刚描述的“要计算”业务,他们只是指数据及其转换。

但是,听起来好像视图只是在表达我们的编码序列,并且只有在传递给一些急切的东西(例如算法)时,它们才会在这个特定的单个调用中表现出所有的计算负载。

后续问题:我可以理解如何实现O(1)副本,本质上是指可复制对象(尽管我不知道这是否是ranges::views这样做的)。但我无法理解这将如何在分配操作中发挥作用。同样,一个可能的答案是,因为所有这些都发生在编译时,那么再次“描述”赋值是一个O(1)操作。但是改变一个std::vector<int>被视图查看的,是一个运行时操作(很好的例子)。这还是O(1)手术吗?

c++ complexity-theory range-v3 c++20 std-ranges

2
推荐指数
1
解决办法
106
查看次数

如何使类与采用范围的 std::span 构造函数兼容?

我希望能够将我的自定义容器传递给这个std::span构造函数:

template< class R >
explicit(extent != std::dynamic_extent)
constexpr span( R&& range );
Run Code Online (Sandbox Code Playgroud)

我需要向自定义类添加什么,以使其满足能够将其传递给std::span接收范围的构造函数的要求?

例如,std::vector我们可以这样做:

std::vector<int> v = {1, 2, 3};
auto span = std::span{v};
Run Code Online (Sandbox Code Playgroud)

我已经将这些添加到我的自定义类中:

Type* begin()
{
    return m_Data;
}

Type* end()
{
    return m_Data + m_Length;
}

const Type* data() const
{
    return m_Data;
}

size_t size() const
{
    return m_Length;
}
Run Code Online (Sandbox Code Playgroud)

...这反过来又允许我使用基于范围的循环,std::data(my_container)以及std::size(my_container). 我还缺少什么才能将容器传递给std::span构造函数?是否需要实现更复杂的迭代器?

c++ c++20 std-span std-ranges

2
推荐指数
1
解决办法
934
查看次数

C++20 中 std::ranges::split_view 的状态是什么?

根据https://en.cppreference.com/w/cpp/ranges/split_viewstd::ranges::split_view自 C++20 起必须可用。然而,同一页面上的示例在其文本中包含“C++23”:

#include <iostream>
#include <iomanip>
#include <ranges>
#include <string_view>
 
int main() {
    constexpr std::string_view words{"Hello-_-C++-_-23-_-!"};
    constexpr std::string_view delim{"-_-"};
    for (const std::string_view word : std::ranges::split_view(words, delim)) {
        std::cout << std::quoted(word) << ' ';
    }
}
Run Code Online (Sandbox Code Playgroud)

GCC 和 MSVC 都拒绝接受 C++20 模式下的这个示例。MSVC 特别打印:

The contents of <ranges> are available only in c++latest mode with concepts support;
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/4fGGb3aqY

-std=c++2bGCC 开始使用命令行开关接受代码(意味着即将推出的 C++23),而 MSVC 即使使用/std:c++latest选项也会报告错误

error C2440: 'initializing': cannot convert from 'std::ranges::split_view<std::basic_string_view<char,std::char_traits<char>>,std::basic_string_view<char,std::char_traits<char>>>::_Outer_iter<true>::value_type' to 'std::basic_string_view<char,std::char_traits<char>>'
note: No …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 std-ranges c++23

2
推荐指数
1
解决办法
2181
查看次数

为什么在 hana:: 中包装对按值返回的函数的调用总是规避 range::views::join 的要求?或者也许不是?

这个函数,输入 any int,返回一个std::vector<int>值:

auto make = [](int){
    return std::vector<int>{1,2,3};
};
Run Code Online (Sandbox Code Playgroud)

因此,这样的事情是行不通的

std::vector<int> v{1,2,3};
auto z = v | std::ranges::views::transform(make)
           | std::ranges::views::join; // fails to compile
Run Code Online (Sandbox Code Playgroud)

因为,我理解(但如果我错了,请纠正我),当迭代器包装在joinadvance 中时,它会通过 触发向量的生成make,但是当迭代器 in 被join取消引用时,这些临时值已经被销毁。

但是,以下操作不会失败:

std::vector<int> v{1,2,3};
auto z = v | std::ranges::views::transform(boost::hana::always(make(int{})))
           | std::ranges::views::join;
Run Code Online (Sandbox Code Playgroud)

这是为什么?使用 引入了什么机制always

我认为以下证明了两个函数make和 都always(make(int{}))返回临时值。我犯错了吗?

static_assert(!std::is_reference_v<decltype(make(int{}))>);
static_assert(!std::is_reference_v<decltype(boost::hana::always(make(int{}))(int{}))>);
Run Code Online (Sandbox Code Playgroud)

完整演示

c++ boost-hana c++20 std-ranges

2
推荐指数
1
解决办法
101
查看次数

range::sort 无法编译

在 MyRect.h 中:

\n
struct MyRect\n{\n    MyRect(std::initializer_list<int> i);\n    MyRect();\n    int16_t m_left=0, m_right=0, m_top=0, m_bottom=0 ;\n    int16_t no_sequence=0 ;\n    int16_t i=-1 ;\n    bool selected=false ;\n} ;\n\nbool operator==(const MyRect& r1, const MyRect& r2) ;\nbool operator<(const MyRect& r1, const MyRect& r2);\n
Run Code Online (Sandbox Code Playgroud)\n

在 MyRect.cpp 中:

\n
bool operator==(const MyRect& r1, const MyRect& r2)\n{\n    return r1.m_left==r2.m_left &&\n        r1.m_right==r2.m_right &&\n        r1.m_top==r2.m_top &&\n        r1.m_bottom==r2.m_bottom ;\n}\nbool operator<(const MyRect& r1, const MyRect& r2)\n{\n    if (r1.m_left != r2.m_left)\n        return r1.m_left < r2.m_left;\n    if (r1.m_right != r2.m_right)\n        return r1.m_right < …
Run Code Online (Sandbox Code Playgroud)

c++ operator-overloading c++20 std-ranges

2
推荐指数
1
解决办法
630
查看次数

对于函数来说,接受对范围而不是视图的转发引用有好处吗?

std::ranges::range在 C++20 之前,当需要将a 作为参数时,有必要在模板函数中使用转发引用。由于 C++20 中提供了概念,因此现在可以将按std::ranges::view值传递给泛型函数。根据标准,视图是一个范围。

考虑以下代码。

#include <vector>
#include <ranges>
#include <iterator>
#include <iostream>

template <std::ranges::range Range>
void fn1(Range range)   // intentionally not a forwarding reference
{
    for (auto& elem : range) {
        ++elem;
    }
}

template <std::ranges::view View>
void fn2(View view)
{
    for (auto& elem : view) {
        ++elem;
    }
}

int main()
{
    std::vector<int> v{1,2,3};
    fn1(v); // doesn't increment, since a copy of 'v' is used in 'fn1'.
    /* fn2(v); // fails to compile, …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20 std-ranges

2
推荐指数
1
解决办法
537
查看次数