我无法让用户定义的容器与 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) 根据 cppreference,帮助类模板view_interface使用奇怪的重复模板模式 (CRTP) 技术定义视图。
它们背后的设计理念是什么?与覆盖派生类中的虚拟基类方法相比,是否有显着的优势?
我运行了以下代码
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.0g++ --version:g++10.2.0为什么 sort 不是成员?advance我正在使用 VScode intellisense,它显示了、begin、等方法common_view。但不排序。
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++20 Ranges 中,我知道views通过使用视图适配器来实现可组合性。我也知道视图不拥有它们的元素,它们的性质是惰性的,也就是说它们只在需要时才进行实际计算。
视图如何实现O(1)移动、复制和分配操作的复杂性?那到我这里来的可能的答案是,意见是刚刚描述的“要计算”业务,他们只是指数据及其转换。
但是,听起来好像视图只是在表达我们的编码序列,并且只有在传递给一些急切的东西(例如算法)时,它们才会在这个特定的单个调用中表现出所有的计算负载。
后续问题:我可以理解如何实现O(1)副本,本质上是指可复制对象(尽管我不知道这是否是ranges::views这样做的)。但我无法理解这将如何在分配操作中发挥作用。同样,一个可能的答案是,因为所有这些都发生在编译时,那么再次“描述”赋值是一个O(1)操作。但是改变一个std::vector<int>被视图查看的,是一个运行时操作(很好的例子)。这还是O(1)手术吗?
我希望能够将我的自定义容器传递给这个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构造函数?是否需要实现更复杂的迭代器?
根据https://en.cppreference.com/w/cpp/ranges/split_view,std::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) 这个函数,输入 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)
完整演示。
在 MyRect.h 中:
\nstruct 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);\nRun Code Online (Sandbox Code Playgroud)\n在 MyRect.cpp 中:
\nbool 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) 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++ ×10
c++20 ×10
std-ranges ×10
range-v3 ×2
boost-hana ×1
c++-concepts ×1
c++23 ×1
g++10 ×1
std-span ×1