7

我有一个template<typename T>需要const vector<T>&. 在所述函数中,我有向量cbegin()cend()size()operator[]。据我了解,两者都string使用vector连续空间,所以我想知道是否可以以优雅的方式重用这两种数据类型的函数。

可以将 astd::string重新解释为std::vector(适当的)char_type 吗?如果是这样,限制是什么?

4

7 回答 7

14

如果您只为类型制作模板const T&并使用向量和字符串共享的begin(),end()等函数,那么您的代码将适用于这两种类型。

于 2015-10-08T21:41:22.620 回答
7

采用 STL 方式并使用迭代器。接受迭代器开始和迭代器结束。它将适用于所有可能的容器,包括流等非容器。

于 2015-10-08T21:44:57.323 回答
6

std::experimental::array_view<const char> n4512表示一个连续的字符缓冲区。

自己写并不难,它解决了这个问题,而且(根据我的经验)还有很多。

字符串和向量都与数组视图兼容。

这使您可以将您的实现移动到一个.cpp文件中(而不是公开它),为您提供与使用相同的性能std::vector<T> const&并且可能相同的实现,避免重复代码,并使用轻量级连续缓冲区类型擦除(其中充满了美味的关键字)。

于 2015-10-08T22:50:25.203 回答
6

不能保证布局stringvector将是相同的。它们理论上可能是,但它们可能不在任何常见的实现中。因此,您不能安全地执行此操作。请参阅 Zan 的答案以获得更好的解决方案。

让我解释一下:如果我是标准库实现者并决定像这样实现 std::string ......

template ...
class basic_string {
public:
    ...
private:
    CharT* mData;
    size_t mSize;
};

并决定像这样实现 std::vector ...

template ...
class vector {
public:
    ...
private:
    T* mEnd;
    T* mBegin;
};

当您reinterpret_cast<string*>(&myVector)结束时,将指向数据末尾的指针解释为指向数据开头的指针,将指向数据开头的指针解释为数据的大小。如果成员之间的填充不同,或者有额外的成员,它也可能变得更奇怪和更破碎。

所以是的,为了让它可能工作,他们都需要存储连续的数据,但他们还需要很多其他的东西在实现之间是相同的才能工作。

于 2015-10-08T21:42:43.527 回答
2

如果关键是您想要访问内存中存储特定字符类型实例的连续区域,那么您可以将函数定义为

void myfunc(const CType *p, int size) {
     ...
}

明确表示您假设它们在内存中必须相邻。

然后例如传递向量的内容,代码很简单

myfunc(&myvect[0], myvect.size());

对于一个字符串

myfunc(mystr.data(), mystr.size());

或者

myfunc(buffer, n);

对于一个数组。

于 2015-10-08T21:48:20.023 回答
1

您不能直接将 std::vector 类型转换为 std::string ,反之亦然。但是使用 STL 容器提供的迭代器确实允许您以相同的方式迭代向量和字符串。如果您的函数需要随机访问相关容器,那么任何一个都可以。

std::vector<char> str1 {'a', 'b', 'c'};
std::string str2 = "abc";

template<typename Iterator>
void iterator_function(Iterator begin, Iterator end)
{
  for(Iterator it = begin; it != end; ++it)
  {
    std::cout << *it << std::endl;
  }
}

iterator_function(str1.begin(), str1.end());
iterator_function(str2.begin(), str2.end());

最后两个函数调用都会打印相同的内容。

现在,如果您想编写一个仅解析仅存储在字符串或向量中的字符的通用版本,您可以编写一些迭代内部数组的东西。

void array_function(const char * array, unsigned length)
{
  for(unsigned i = 0; i < length; ++i)
  {
    std::cout << array[i] << std::endl;
  }
}

在以下情况下,这两个函数都会做同样的事情。

std::vector<char> str1 {'a', 'b', 'c'};
std::string str2 = "abc";

iterator_function(str1.begin(), str1.end());
iterator_function(str2.begin(), str2.end());
array_function(str1.data(), str1.size());
array_function(str2.data(), str2.size());

总是有多种方法可以解决问题。根据您可用的内容,任何数量的解决方案都可能有效。尝试两者,看看哪个更适合您的应用程序。如果您不知道迭代器类型,那么 char 类型的数组迭代很有用。如果你知道你总是要传入模板类型,那么模板迭代器方法可能会更有用。

于 2015-10-08T21:46:17.550 回答
1

您现在提出问题的方式有点令人困惑。如果您的意思是问“如果向量恰好包含适当类型的 char 值,将std::vector类型转换为std::string类型是否安全?反之亦然?”,答案是:不可能,甚至不要考虑它!如果您问:“如果它们是 char 类型std::vector或char 类型的非空序列,我可以访问它们的连续内存std::string吗?” 那么答案是,是的,你可以(使用data()成员函数)。

于 2015-10-09T07:57:30.373 回答