看起来 C++20 中的 std::span
定义类似于
template<class T>
class span
{
T* begin;
size_t count;
};
而不是
template<class Iter>
class span
{
Iter begin;
Iter end;
};
哪个更通用(适用于std::list, std::map等)?
std::span<T>
的整个意义在于它是对于连续数据的一种视图。使用pair<T*, size_>
(或类似的类型)来表示这种视图是正确的方式。你不能有一个std::span
是针对std::list
或std::map
的视图,因此想出一种表示方法是没有意义的。重点是要成为一种通用的词汇类型,只接受连续的数据。span
实际上是类型擦除的。一个span<int>
可以引用到一个int[20]
、一个vector<int>
或者一个动态分配的int[]
,或者一个llvm::SmallVector<int>
等等。它的来源并不重要,你只需要这一个类型:"查看一些连续的int
"。pair<Iter, Iter>
(或更一般的情况下,pair<Iter, Sentinel>
)是一种更通用的表示方法,适用于更多的容器。在C++20中也有这样一种东西,它被称为std::ranges::subrange<I, S>
。但是请注意,这里没有类型擦除的方面...一个针对map<K, V>
的subrange
将具有不同的类型,而一个针对相同value_type
的不同容器的subrange
,如list<pair<K const, V>>
、vector<pair<K const, V>>
或multimap<K, V>
。
subrange<T*>
在表示上基本上等同于span<T>
。但它们的可用性不同。vector<T>
明确可以转换为span<T>
,但不一定可以转换为subrange<T*>
。此外,模板参数的意义也不同,即T
与T*
。span
只是更具体用例的更具体东西。 - Barryspan
的数据传递给C API;而对于任意迭代器子范围,你不能这样做。 - Nicol Bolassubrange<T*> range{vec.data(), vec.data() + size()};
就是正确的。 - user877329Iter
是一个指针,我应该能够这样做。即使我可以将其传递给C API,也必须存在这样的API,大多数C API使用指针和大小,而不是跨度结构,因此C兼容性并不是一个很大的问题,除非您重写POSIX或Windows API以及一堆其他C库,但您没有这样做。当然,可能会发生调用foo(T*,size_t)
与foo(std :: span <T>)
在汇编中看起来完全相同,但强制不同的函数签名绝对是未定义行为。 - user877329