2013-03-03 61 views
7

C++标准库提供了多种用于为容器对象指定接口的“概念”。例如,std::vector实现了Container,Sequence,RandomAccessContainerReversibleContainer概念。C++连续序列概念

是否有一个概念,无论是在指定的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提供连续内存的类?

+4

'std :: array';) – Zeta 2013-03-03 17:55:54

+8

据我所知,没有这样的概念。 'std :: vector','std :: string'和'std :: array'在[[0,c]中只有'c.data()+ i ==&c [i]'''''的不变量.size())'。 – Xeo 2013-03-03 17:56:07

+1

@Xeo:对。没有概念,只有要求元素(或'char_type's)*“连续存储”*。 – Zeta 2013-03-03 17:57:06

回答

0

从C++ 03,仅std::vector保证(23.2.4.1):

向量的元素被存储 连续,这意味着如果v是 向量,其中T是一些 类型不是bool,那么它服从 标识& v [n] == & v [0] + n对于 全部0 < = n < v.size()。

C++ 11增加了std :: array,它是固定大小数组的封装并且也具有相同的属性。我不认为有任何方法可以知道任何集装箱是否拥有此类财产。

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.data()更换例如t[0]

2)使用某种SFINAE对.data()

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函数(或.data()在C++ 11),该指针返回到值类型然后 是连续的元素。

(好吧,那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.pdfhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html

3

“毗连容器” 是specifed在C++ 17两个提案。从$23.2.1/13 General container requirements [container.requirements.general]

甲邻接容器是支持随机访问迭代([random.access.iterators]),其成员类型iterator和常量性是连续的迭代([iterator.requirements.general])的容器。

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

迭代器进一步满足的是,对于整数值n和提领迭代值A和(A + N)的要求,*(A + N )等价于*(addressof(* a)+ n),称为连续迭代器。

std::vector(除了std::vector<bool>std::arraystd::basic_string是连续的容器。

+0

不错。是否明确说明哪些容器是连续的?我认为'std :: valarray'和plain应该在列表中。平原阵列呢? – 2016-07-16 10:17:29

+2

@JohanLundberg我试过搜索标准,似乎只有我的答案中提到的3个容器是“连续容器”。 'std :: valarray'和普通数组不是“连续的容器”,因为它们是“连续的”而不是“容器”。 – songyuanyao 2016-07-16 10:32:38