Программирование >>  Разработка устойчивых систем 

1 ... 114 115 116 [ 117 ] 118 119 120 ... 196


class Delimiters : std::unary function<char. bool> {

std::string exclude: public:

DelimitersO {}

Del1miters(const std::string& excl) : exclude(excl) {} bool operatorO (char c) { return exclude.find(c) == std::string::npos:

template <class Inputlter. class Pred = Isalpha> class Tokenlterator : public std::iterator<

std::input iterator tag,std::string, std::ptrdiff t> \

Inputlter first:

Inputlter last:

std::string word:

Pred predicate: public:

TokenIterator(Inputlter begin, Inputlter end. Pred pred = PredO)

: first(begin), last(end), predicate(pred) { ++*this:

TokenlteratorO {} Конечный итератор Префиксный инкремент: TokenlteratorS operator++() { word.resize(O):

first = std:: findjf (first, last, predicate): while (first != last && predicate(*first))

word += *first++: return *this:

Постфиксный инкремент class CaptureState { std::string word: public:

CaptureState(const std::string& w) : word(w) {} std::string operator*() { return word: }

CaptureState operator++(int) { CaptureState d(word): ++nhis: return d:

Разыменование (выборка значения): std::string operator*() const { return word: } std::string* operator->() const { return &(operator*()): Сравнение итераторов: bool operator==(const TokenlteratorS) { return word.sizeO =- 0 && first == last:

bool operator!=(const TokenlteratorS rv) { return !(*this == rv):

lendif TOKENITERATOR H /:-

bool operatorO(char с) { return std::isalpha(c): }



Класс Tokenlterator объявляется производным от шаблона std::i*terator. Может показаться, что он использует какие-то функциональные возможности шаблона std::iterator, но на самом деле это всего лишь способ пометить итератор, то есть передать контейнеру информацию о том, что он может делать. В аргументе шаблона, определяющем категорию итератора, передается значение input iterator tag - оно сообщает, что Tokenlterator обладает минимальными возможностями итератора ввода и не может использоваться с.алгоритмами, для которых нужны более совершенные итераторы. В остальном шаблон std::iterator не делает ничего, помимо определения нескольких полезных типов. Всю полезную функциональность нам придется реализовать самостоятельно.

Класс Tokenlterator выглядит несколько странно: первому конструктору наряду с предикатом должны передаваться итераторы (начальный и конечный). Но как отмечалось выше, Tokenlterator - всего лишь оболочка; он не узнает о достижении конца входных данных, поэтому присутствие конечного итератора в первом конструкторе необходимо. Наличие второго конструктора (конструктора по умолчанию) объясняется тем, что в алгоритмах STL, а также в пользовательских алгоритмах вызов конструктора без аргументов означает конец перебора. Но вся информация, по которой определяется достижение итератором Tokenlterator конца входных данных, собрана в первом конструкторе. Таким образом, второй конструктор создает объект Tokenlterator, который просто занимает положенное место в алгоритмах.

Вся основная функциональность класса сосредоточена в операторе ++. Он уничтожает текущее значение word вызовом string::resize(), а затем ищет первый символ, удовлетворяющий предикату (то есть начало новой лексемы), алгоритмом find if(). Полученный итератор присваивается переменной first, в результате чего first перемещается в начало новой лексемы. Затем до тех пор, пока не будет достигнут конец входных данных, удовлетворяющие предикату входные символы копируются в word. В завершение своей работы префиксный инкремент возвращает объект Tokenlterator. Чтобы обратиться к новой лексеме, достаточно разыменовать этот итератор.

В случае с постфиксным инкрементом необходим промежуточный объект CaptureState, в котором сохраняется старое значение для его последующего возвращения.

Для получения текущего значения используется обычный оператор разыменования *. Далее остается лишь определить операторные функции operator== и operator!= для проверки достижения конца входных данных. Как видно из листинга, аргумент функции operator== игнорируется - итератор просто проверяет, достигнут ли его внутренний итератор last. Обратите внимание на то, как operator!= определяется через operator==.

Качественный тест Tokenlterator должен включать различные источники входных символов, в том числе streambufjterator, char* и deque<char>::iterator. В конце программы решается исходная задача со списком слов:

: C07:TokenIteratorTest.cpp {-g++}

#include <fstream>

#include <iostream>

#include <vector>

#include <deque>

#include <set>

#inc1ude Tokenlterator.h



linclude ../require.h using namespace std:

int main(int argc. char* argv[]) { char* fname = TokenlteratorTest.cpp : if(argc > 1) fname = argv[l]: ifstream in(fname): assure(in. fname):

ostream iterator<string> out(cout. \n ): typedef istreambuf iterator<char> Isbit: Isbit begin(in). isbEnd: Delimiters

delimiters( \t\n~:()\ <>:{}[]+-=&*#. ./W ): TokenIterator<IsbIt. Delimiters> wordIter(begin. isbEnd, delimiters), end:

vector<string> wordlist:

copy(wordIter, end, back inserter(wordlist)):

Вывод результата:

copy (wordlist. begi n(). wordlist.endO. out):

*out++ = ........-------............-------- :

Получение данных из символьного массива: char* ср =

typedef std::istreambuf iterator<char> It : TokenIterator<char*. Delimiters> charlter(cp. cp + strlen(cp). delimiters). end2:

vector<string> wordlist2:

copy(charIter, end2, backjnserter(wordlist2)):

copy(wordlist2.beginO. wordlist2.end(). out):

*out++ = -...............------............. :

Получение данных из deque<char>: ifstream in2( TokenlteratorTest.cpp ): deque<char> dc:

copy(IsbIt(in2). IsbltO. back inserter(dc)): TokenIterator<deque<char>::iterator.Delimiters>

dclter(dc.beginO. dc.endO, delimiters).

end3:

vector<string> wordl istS:

copy(dcIter, end3. back inserter(wordlist3)):

copy (wordl ist3. beginO. wordl ist3.end(), out):

*out++ = ......................------------- :

Повторение примера Wordlist.cpp: ifstream in3( TokenlteratorTest.cpp ): TokenIterator<IsbIt. Delimiters>

wordIter2((IsbIt(in3)). isbEnd. delimiters): set<string> wordlist4: while(wordIter2 != end)

wordli st4.i nsert(*wordIter2++): copy(wordlist4.beginO. wordlist4.end(). out): } III-

В тесте istreambufjterator создаются два итератора: один присоединяется к объекту istream, а другой создается конструктором по умолчанию и отмечает конец интервала. Оба итератора используются для создания объекта Tokenlterator, разбирающего входной поток на лексемы; конструктор по умолчанию создает фальшивый объект Tokenlterator, изображающий конечный итератор (в действительности он просто занимает положенное место и игнорируется). Объект Tokenlterator создает



1 ... 114 115 116 [ 117 ] 118 119 120 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика