C ++连续序列概念

时间:2013-03-03 17:53:21

标签: c++ c++11 containers std language-lawyer

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

是否存在一个在C ++ 03或C ++ 11中指定的概念,它描述了Sequence,它保证了元素之间的连续内存,因此:

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

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

我知道,实际上,只有std::vector(我认为只有C ++ 11中的std::string)实际上保证了一个基础的连续缓冲区 - 但这是std::vector唯一的保证或者是否有一个定义的“概念”,表示提供连续内存的通用Sequence类?

3 个答案:

答案 0 :(得分:3)

“Contiguous container”在C ++ 17中指定。来自$23.2.1/13 General container requirements [container.requirements.general]

  

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

关于“连续迭代器”,$24.2.1/5 In general [iterator.requirements.general]

  

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

std::vectorstd::vector<bool>除外),std::arraystd::basic_string是连续的容器。

答案 1 :(得分:1)

我发现自己必须多次识别完成此功能的类型。我不知道发明这样一个特殊的“概念”是否优雅(想象它是一个涉及记忆的概念,这不是很抽象)但我同意这样的事情会有用。

同时为了实用并将将此概念/要求转换为纯语法要求,让我们向后走。如果我们将自己局限于标准,那么保证(或几乎保证)邻接的类别是什么?按相关顺序:

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[0]替换为*t.data()

,则不难

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>重载。 因此,您可以将上面的....data()替换为std::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

答案 2 :(得分:0)

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

  

存储向量的元素   连续地,意思是如果v是a   矢量,其中T是一些   除了布尔之外的类型,然后它服从   身份&amp; v [n] ==&amp; v [0] + n for   全0&lt; = n&lt; v.size()。

C ++ 11添加了std :: array,它是固定大小数组的包装器,也具有相同的属性。我不认为有办法知道任何容器是否有这样的财产。