C ++标准库提供了各种“概念”,用于指定容器对象的接口。例如,std::vector
实现了Container
,Sequence
,RandomAccessContainer
和ReversibleContainer
概念。
是否存在一个在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
类?
答案 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::vector(std::vector<bool>
除外),std::array和std::basic_string是连续的容器。
答案 1 :(得分:1)
我发现自己必须多次识别完成此功能的类型。我不知道发明这样一个特殊的“概念”是否优雅(想象它是一个涉及记忆的概念,这不是很抽象)但我同意这样的事情会有用。
同时为了实用并将将此概念/要求转换为纯语法要求,让我们向后走。如果我们将自己局限于标准,那么保证(或几乎保证)邻接的类别是什么?按相关顺序:
std::vector<T>
T[N] // !!
std::array<T, N>
std::string
std::initializer_list<T>
std::valarray<T>
在所有这些中,std::vector
,std::array
,std::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,它是固定大小数组的包装器,也具有相同的属性。我不认为有办法知道任何容器是否有这样的财产。