最近我有建议span<T>在我的代码中使用's,或者在网站上看到了一些使用span's - 应该是某种容器的答案.但是 - 我在C++标准库中找不到类似的东西.
那么这个神秘的是什么span<T>,以及为什么(或什么时候)使用它是一个好主意,如果它是非标准的?
一般来说,C++ 不允许比较不同容器之间的迭代器。例如:
int main() {
std::vector<int> v = {1, 2, 3};
std::vector<int> w = {4, 5, 6};
std::cout << v.end() == w.end() << std::endl; // undefined!
}
Run Code Online (Sandbox Code Playgroud)
但是对于使用 创建的子跨度来说也是如此吗std::span::subspan()?例如:
int main() {
int a[4] = { 1, 2, 3, 4};
std::span<int> s(a);
std::span<int> t = s.subspan(1, 2);
std::cout << t.begin() - s.begin() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这会打印1,这是预期的,因为内部迭代器可能只是指向底层数组的指针。问题是:该标准能否保证其正常工作?
如果是这样,更一般地说,我是否还可以比较来自内存中同一连续对象的任何跨度的迭代器?例如:
int main() {
int a[5] = { 1, 2, 3, 4, 5};
std::span<int> s(a);
std::cout << (s.subspan(1, 1).end() < …Run Code Online (Sandbox Code Playgroud) 我一直在研究std::span在Godbolt上使用clang干线和libc ++ 的最新规范,并发现一些令人困惑的构造函数。
特别是,我从一个普通的旧数组中发现了构造函数,并且a std::array与其他容器不同。
例如,以下代码似乎可以编译:
std::vector<int*> v = {nullptr, nullptr};
std::span<const int* const> s{v};
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
std::array<int*, 2> a = {nullptr, nullptr};
std::span<const int* const> s{a};
Run Code Online (Sandbox Code Playgroud)
这似乎与cppreference.com上描述构造函数的方式保持一致,我只是在努力理解为什么是这种情况。有人可以照亮吗?
不是std::span设计为轻量参考的子区域std::vector/ std::array/普通数组和相似吗?它不应该在其 API 中也包含比较运算符,以与它们保持一致吗?排除背后的原因是什么?
注意:通过比较运算符,我的意思是完整的集合 ( <, <=, ...) 或宇宙飞船<=>
我知道这可能与问题重叠:什么是 \xe2\x80\x9cspan\xe2\x80\x9d 以及我何时应该使用它?,但我认为问题的这个特定部分的答案相当令人困惑。一方面,有这样的引用:
\n\n\n如果您有一个标准库容器(或 Boost 容器等),并且您知道它最适合您的代码,请不要使用它。它无意取代其中任何一个。
\n
但在同一个答案中,出现了这样的说法:
\n\n\n当您希望数据在内存中连续时,是将 const vector& 传递给函数的合理替代方案。再也不用被 C++ 大师骂了!
\n
那么我没有到达哪一部分呢?我什么时候会这样做:
\nvoid foo(const std::vector<int>& vec) {}\nRun Code Online (Sandbox Code Playgroud)\n而这是什么时候呢?
\nvoid foo(std::span<int> sp) {}\nRun Code Online (Sandbox Code Playgroud)\n还有,这会不会
\nvoid foo(const std::span<int> sp) {}\nRun Code Online (Sandbox Code Playgroud)\n有什么意义吗?我认为不应该,因为 astd::span只是 a struct,包含指针和长度。但是,如果它不能阻止您更改std::vector作为参数传递的值,那么它如何替换const std::vector<T>&?
根据某种条件在几个已知范围之一上进行迭代的最有效方法是什么?
二进制条件的伪代码:
for element in (condition ? range_a : range_b)
// do work
Run Code Online (Sandbox Code Playgroud)
这个“示例”显示了我使用基于范围的for循环的意图,但由于std::initializer_list具有参考语义,因此无法使用。
for element in (condition ? range_a : range_b)
// do work
Run Code Online (Sandbox Code Playgroud)
产量: warning: returning address of local temporary object [-Wreturn-stack-address]
在运行时,我可以返回a,std::vector但这将涉及在每次调用时构造一个新的向量:
constexpr auto some_range(bool c) -> std::initializer_list<int> {
if (c) {
return {1,2};
} else {
return {3, 4, 5};
}
}
bool cond = true; // false
for(auto x : some_range(cond)) {
// things
}
Run Code Online (Sandbox Code Playgroud)
我可以使用的固定大小std::array …
在以下 C++20 代码中,将 a 传递std::vector给带有参数的模板化函数std::span<T>会失败,因为显然编译器无法推导出模板参数。我已经用 GCC、Clang 和 MSVC 尝试过了;全部失败。
像这样调用有效:f3(std::span(vi))或f3(std::span(vp))。
我想知道为什么会失败,因为在我的理解中,std::vector是一个范围,并且std::span有范围的推导指南。
#include <memory>
#include <vector>
#include <span>
void f1(std::span<int> s)
{
}
void f2(std::span<std::shared_ptr<int>> s)
{
}
template<typename T>
void f3(std::span<T> s)
{
}
int main(int argc, char* argv[])
{
std::vector<int> vi;
std::vector<std::shared_ptr<int>> vp;
f1(vi);
f2(vp);
f3(vi); // ERROR: no matching function for call to 'f3'
f3(vp); // ERROR: no matching function for call to …Run Code Online (Sandbox Code Playgroud) std::span已被选入C ++ 20。我假设与一起std::span将有一个方便的别名,定义如下:
template <class T, size_t Extent = dynamic_extent>
using cspan = span<const T, Extent>;
Run Code Online (Sandbox Code Playgroud)
对我来说,这似乎是一个非常方便的别名。我可能cspan会比使用更多span!根据cppreference,cspan不存在。有一个提到cspan在本文中这似乎暗示,是在一些点的标准。我找不到其他提及。
那怎么了cspan?它被删除了吗?它曾经存在过吗?
在过去一年左右的时间里,我注意到 StackOverflow 上有一些与 C++ 相关的答案mdspan,但我从未在 C++ 代码中真正看到过这些答案。我尝试在 C++ 编译器的标准库目录和C++ 编码指南中查找它们- 但找不到它们。我确实找到了std::span;我猜它们是相关的——但是如何呢?添加“md”代表什么?
请解释一下这个神秘实体的用途,以及我何时需要使用它。
我一直在更新使用homebrew span类的旧代码,使之更符合C ++ 20的要求,std::span并且由于std::span没有size_type和有,我遇到了编译错误index_type。关于是否index_type应该签名已经发生了巨大的变化,但是为什么要跳过size_type呢?这会破坏期望容器(或类似容器的对象)具有的通用代码size_type。