c++连续序列概念

C++ Contiguous Sequence Concept

本文关键字:连续 c++      更新时间:2023-10-16

c++标准库提供了各种"概念",用于指定容器对象的接口。例如,std::vector实现了ContainerSequenceRandomAccessContainerReversibleContainer的概念。

是否有一个概念,在c++ 03或c++ 11中指定,描述一个Sequence来保证元素之间的连续内存,以便:

static_cast<void*>(&some_sequence[N]) == static_cast<void*>(&some_sequence[0] + N)>

这将是一个有用的概念,因为它告诉您是否可以将容器用于任何需要连续内存缓冲区的函数,例如std::istream::read

我知道,在实践中,只有std::vector(我认为std::string在c++ 11中只有)实际上保证了一个底层的连续缓冲区-但是这个保证是std::vector独有的,还是有一个定义的"概念",表明一个通用的Sequence类提供连续内存?

"连续容器"在c++ 17中被指定。从$23.2.1/13起一般集装箱要求[container.requirements. General]:

连续容器是支持随机访问迭代器([random.access.iterators])的容器,其成员类型iterator和const_iterator都是连续迭代器([iterator.require .general])。

关于"连续迭代器",一般$24.2.1/5[iterator.requirements.general]:

进一步满足以下要求的迭代器称为连续迭代器:对于整型值n和可解引用迭代器值a和(a + n), *(a + n)等于*(addressoft (*a) + n)。

std::vector (std::vector<bool>除外)、std::array和std::basic_string是连续的容器。

我发现自己不得不多次识别满足此特性的类型。我不知道发明这样一个特殊的"概念"是否优雅(想象它是一个涉及记忆的概念,这不是很抽象),但我同意这样的东西将是有用的。

同时,为了实用,把这个概念/需求转换成一个纯语法需求,让我们往回走。如果我们将自己限制在标准中,那么保证(或几乎保证)连续性的类是什么?按相关顺序:
std::vector<T>
T[N] // !!
std::array<T, N>
std::string
std::initializer_list<T>
std::valarray<T>

其中std::vectorstd::arraystd::string有一个成员函数.data()。因此,如果这对您来说足够了,可以依赖成员.data() -> T*的存在来表示连续内存。

你有两个选择:

1)让努力使用成员函数.data()来引发语法错误,如果类型不是连续的。(如果你用*t.data()代替t[0]也不难)

2)在.data()上使用某种SFINAE。

template<class ContiguousSequence, typename = decltype(std::declval<ContigiousSequence>().data())>
void fun(ContiguousSequence&& s){...} // this function will only work with contiguous data

此外,c++ 17有std::data,它将.data()泛化到所有类型,并为T[N]std::initializer_list<T>附加了重载。所以,你可以用上面的std::data(...)代替....data()

结论,我认为这是一个很好的惯例是如果一个类型有一个data函数(或c++ 11中的.data()函数),该函数返回一个指向该值类型的指针,则该元素是连续的。

(好的,std::valarray<T>呢?它不起作用,除非你重载std::data(std::valarray<T>&)。但是谁会使用std::valarray呢?我认为这是c++中一个被遗弃的角落)

最后,请注意,例如,明显的std::map和不太明显的std::deque没有.data()(或std::data(...))函数。boost::multi_array<..., N>有一个.data()成员,并返回一个指向数组元素的指针,它不清楚这是否是你想要的连续序列(因为顺序不明显),但在某种意义上它也是一个连续的内存分配。

编辑:

目前有两个建议解决这个问题(但是在迭代器级别)http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html

从c++ 03开始,只有std::vector保证(23.2.4.1):

vector的元素是存储的连续的,意思是如果v是a向量,其中T是输入bool以外的类型,则服从v[n] == &v[0] + n for所有0 <= n

虽然这个问题是专门针对c++ 11提出的,但我觉得至少值得注意的是,c++ 20为此引入了一个名为std::ranges::contiguous_range的适用概念,因为容器基本上是一个范围。例如:

#include <list>
#include <ranges>
#include <vector>
static_assert(not std::ranges::contiguous_range<std::list<int>>);
static_assert(std::ranges::contiguous_range<std::vector<int>>);