Интерпретировать std :: string как std :: vector типа char_type?

у меня есть template<typename T> функция, которая принимает const vector<T>&, В указанной функции у меня есть векторы cbegin(), cend(), size(), а также operator[],
Насколько я понимаю, оба string а также vector использовать непрерывное пространство, поэтому мне было интересно, смогу ли я повторно использовать функцию для обоих типов данных элегантным способом.

Может std::string быть истолковано как std::vector из (соответствующих) char_type? Если да, то какими будут ограничения?

6

Решение

Если вы делаете свой шаблон только для типа const T& и использовать begin(), end()и т. д., функции, которые совместно используют вектор и строку, тогда ваш код будет работать с обоими типами.

13

Другие решения

Идите по пути STL и используйте итераторы. Принять итератор, чтобы начать и итератор до конца. Он будет работать со всеми возможными контейнерами, включая не контейнеры, такие как потоки.

7

Там нет гарантии макета string а также vector будет таким же. Теоретически они могут быть, но они, вероятно, не в какой-либо общей реализации. Поэтому вы не можете сделать это безопасно. Смотрите ответ Зана для лучшего решения.

Позвольте мне объяснить: если я являюсь разработчиком стандартной библиотеки и решил реализовать 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) Вы интерпретируете указатель на конец ваших данных как указатель на начало ваших данных, а указатель на начало ваших данных — на размер ваших данных. Если отступы между членами различны, или есть дополнительные члены, это может стать еще более странным и более разрушительным, чем это.

Так что да, для того, чтобы это, возможно, работало, им обоим нужно хранить смежные данные, но им также нужно немного другое, чтобы они были одинаковыми между реализациями, чтобы он работал.

6

std::experimental::array_view<const char> n4512 представляет собой непрерывный буфер символов.

Пишу твой собственный не сложно, и это решает эту проблему и (по моему опыту) еще много.

И строка, и вектор совместимы с представлением массива.

Это позволяет вам переместить вашу реализацию в .cpp файл (и не подвергать его), дает вам ту же производительность, что и с std::vector<T> const& и, вероятно, та же самая реализация, избегает дублирования кода и использует легкое стирание непрерывного типа буфера (которое полно вкусных ключевых слов).

5

Если ключевым моментом является то, что вы хотите получить доступ к непрерывной области в памяти, где хранятся экземпляры определенного типа символов, тогда вы можете определить свою функцию как

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

чтобы было ясно, что вы предполагаете, что они должны быть смежными в памяти.

Затем, например, чтобы передать содержимое вектора, код просто

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

и для строки

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

или же

myfunc(buffer, n);

для массива.

2

Вы не можете напрямую указать тип 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());

Всегда есть несколько способов решить проблему. В зависимости от того, что у вас есть, может подойти любое количество решений. Попробуйте оба варианта и посмотрите, какой из них лучше подходит для вашего приложения. Если вы не знаете тип итератора, тогда итерация массива с типом символа будет полезна. Если вы знаете, что у вас всегда будет тип шаблона для передачи, то метод итератора шаблона может быть более полезным.

1

То, как ваш вопрос задан в данный момент, немного сбивает с толку. Если вы хотите спросить «безопасно ли бросить std::vector введите в std::string тип или наоборот, если вектор содержит значения char соответствующего типа? », ответ: нет, даже не думайте об этом! Если вы спрашиваете:« Могу ли я получить доступ к непрерывной памяти не пустые последовательности типа char, если они относятся к типу std::vector или же std::string? »тогда ответ, да, вы можете (с data() функция-член).

0