|
Программирование >> Разработка устойчивых систем
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 создает
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |