3

我正在编写一些基于容器或可迭代的算法。for( : )基本上,我对支持样式迭代的对象进行操作(我很少for( : )直接使用,但遵循它如何查找beginend迭代器)。

std库中,大多数可迭代对象都是容器。他们都拥有自己的数据,并让您查看。

当算法通过右值引用获取容器时,这意味着容器的内容也可以自由获取。例如,如果我写concatinate了两个vectors 并返回第三个,如果两个vectors 都是moved,我们将希望重用第一个,vector然后使用move_iterators 从第二个中取出数据vector以提高效率。

但是,对于概念上相似的 C++1ystring_view和类型,我们拥有不是容器的可迭代对象,而是容器中的视图。从语义上讲,我相信视图的行为类似于指针,因此它们的“按值”复制是将视图复制到容器中,而不是它们引用的数据。如果我string_view通过右值引用来获取样式视图,这并不意味着它拥有内容:从内容移动是不合理的,只是因为指针本身是右值而移动指针的内容。

同时,容器遵循值语义,并且因为它们是右值而移动它们的内容是有效的。

因为string_view这不是问题,但我编写了更通用的view类,例如contiguous_range_view,它可以让您对 avectorarrayor的子集进行操作,arr[]就好像它是一个大小不可变的缓冲区一样。

这些视图并不总是将其内容视为const,但它们并不拥有其内容。所以视图是右值并不意味着它们的内容是右值!

我的算法喜欢concatinate在这里遇到问题。视图与容器几乎没有区别,右值容器可以有效地被移出,而右值视图则不是。按值返回视图的函数是一种很好的模式,因为视图在语义上是指针类型。

我正在寻找一种很好、干净的方式来区分容器和视图。是否有计划string_view通过我现在可以模拟或挂钩的某些属性或标签在 C++1y 中进行区分?如果没有,有没有好的模式?

如果我设法阻止视图被意外移动,有时我仍然需要能够从它们移动,所以我需要一种方法来将视图标记为移动候选而不是右值引用. 我怀疑一个make_move_range函数可能会解决这个问题(它需要一个可迭代的范围,并适用std::make_move_iteratorbeginand end)。

4

3 回答 3

2

Container选项1:我认为和View概念之间最明显的区别是容器有inserterase操作,而视图没有。我会尝试使用这个事实来编写一个类型特征来检测Container-ness。具体来说,我认为所有标准容器都有一个void erase(iterator)成员。

选项 2:容器管理内存,视图不管理。标准容器都有一个成员typedef allocator_type

值得注意的是,这些观察结果都不适用于std::array内置数组。

于 2013-07-12T14:43:51.433 回答
1

如果目标是区分std::stringand std::string_view,我会使用这样的东西:

template <
class String = std::string, 
class = typename std::enable_if<!std::is_void<decltype(std::declval<String>().substr(0))>::value>::type // Check if the type has the substr member
>
constexpr bool is_view(const String& str = String())
{
    return std::is_nothrow_constructible<String, std::string>::value;
}

作为容器,应该管理内存,它们的构造函数不是 nothrow,而容器视图似乎有 nothrow 构造函数。

编辑:感谢凯西的回答,我认为这种检测类型是视图还是容器的元函数(假设视图不是微不足道的对象而是数组)会起作用。

template <class Type>
constexpr bool is_view()
{
    return (!std::is_trivial<Type>::value) 
        && (!std::is_constructible<Type, 
             std::allocator<typename Type::value_type>>::value);
}
于 2013-07-12T14:49:20.223 回答
0

也许这种一般模式会有所帮助:

struct Container
{
    CopyIterator begin() &;
    CopyIterator end() &;
    MoveIterator begin() &&;
    MoveIterator end() &&;
};

struct View
{
    CopyIterator begin();
    CopyIterator end();
};
于 2013-07-12T14:33:06.467 回答