v.push_back(string('fum'));
join(v, '/', s);
cout << s << '
';
}
Пример 4.13 содержит одну методику, которая несколько отличается от предыдущие примеров. Посмотрите на эту строку.
for (vector<string>::const_iterator p = v.begin();
Предыдущие примеры работы со строками использовали iterator
'ы без части «const», но здесь без этого не обойтись, так как v
объявлен как ссылка на объект const
. Если имеется объект контейнера const
, то для доступа к его элементам можно использовать только const_iterator
. Это так потому, что простой iterator
позволяет записывать в объект, на который он указывает, что, конечно, нельзя делать в случае с объектами контейнера типа const
.
v
объявлен как const
по двум причинам. Во-первых, я знаю, что я не собираюсь изменять его содержимое, так что я хочу, чтобы компилятор выдал сообщение об ошибке, если это произойдет. Компилятор гораздо лучше меня в деле поиска таких вещей, особенно когда к такому присвоению приводит тонкая семантическая или синтаксическая ошибка. Во-вторых, я хочу показать пользователям этой функции, что я ничего не делаю с их контейнером, и const
— это великолепный способ сделать это. Теперь я просто должен создать обобщенную версию, которая работает с различными типами символов.
Как и в рецепте 4.6, превращение join
в общий шаблон функции очень просто. Все, что требуется сделать, — это изменить заголовок, параметризовав тип символов, как здесь:
template<typename T>
void join(const std::vector<std::basic_string<T> >& v, T c,
std::basic_string<T>& s)
Но vector
может оказаться не единственным возможным входом функции. Вам может потребоваться объединить строки в стиле С. Класс string
C++ предпочтительнее строк в стиле С, так что если возникает такая задача, объединяйте их в C++ string
. После этого всегда можно получить версию С, вызвав метод string c_str
, который возвращает указатель const
на завершающийся нулем массив символов.
Пример 4.14 предлагает общую версию join
, которая объединяет массив символов в string
. Так как новая общая версия параметризована по типу символов, она будет работать как для массивов узких, так и для массивов широких символов.
#include <string>
#include <iostream>
const static int MAGIC_NUMBER = 4;
template<typename T>
void join(T* arr[], size_t n, T c, std::basic_string<T>& s) {
s.clear();
for (int i = 0; i < n; ++i) {
if (arr[i] != NULL)
s += arr[i];
if (i < n-1) s += c;
}
}
int main() {
std::wstring ws;
wchar_t* arr[MAGIC_NUMBER];
arr[0] = L'you';
arr[1] = L'ate';
arr[2] = L'my';
arr[3] = L'breakfast';
join(arr, MAGIC_NUMBER, L'/', ws);
}
4.9. Поиск в строках
Требуется выполнить поиск в строке. Это может быть поиск одного символа, другой строки или одного из (или одного
Используйте один из методов «find» из basic_string
. Почти все методы поиска начинаются со слова «find», и их имена говорят достаточно о том, что они делают. Пример 4.15 показывает, как работают некоторые из этих методов поиска.
#include <string>
#include <iostream>
int main() {
std::string s = 'Charles Darwin';
std::cout << s.find('ar') << '
'; // Поиск от
// начала
std::cout << s.rfind('ar') << '
'; // Поиск с конца
std::cout << s.find_first_of('swi') // Найти первое вхождение одного
<< '
'; // из этих символов
std::cout << s.find_first_not_of('Charles') // Найти первое,
<< '
'; // что не входит в этот
// набор
std::cout << s.find_last_of('abg') << '
'; // Найти первое вхождение любого
// из этих символов,
// начиная с конца
std::cout << s.find_last_not_of('aDinrw') // Найти первое,
<< '
'; // что не входит в этот
// набор, начиная с конца
}
Все эти методы поиска обсуждаются более подробно в разделе «Обсуждение».
Имеется шесть различных методов для поиска в строках, каждый из которых предоставляет четыре перегруженных варианта. Эти перегрузки позволяют использовать либо параметр