Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Warming up

Boost , Spirit 2.5.2 , Tutorials

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Как научиться использоватьДух. кармаЭто очень просто. Мы начнем с тривиальных примеров, увеличиваясь по мере продвижения.

Trivial Example #1 Generating a number

Давайте создадим генератор, который выведет число с плавающей запятой:

double_

Легко, да? Приведенный выше код фактически инстанцирует генератор с плавающей точкой Spirit (встроенный генератор). Spirit имеет много заранее определенных генераторов, и согласованные соглашения об именах помогут вам найти свой путь через лабиринт. Особенно важно отметить, что вещи, связанные с идентичными сущностями (как в данном случае, числа с плавающей запятой), называются одинаково в духе. кармаи вДух.Ки. На самом деле обе библиотеки используют один и тот же переменный экземпляр для обозначения генератора или парсера с плавающей запятой:<double_>.

Trivial Example #2 Generating two numbers

Теперь давайте создадим генератор, который выведет линию, состоящую из двух чисел с плавающей запятой.

double_ << double_

Здесь вы видите знакомый генератор чисел с плавающей точкой<double_>, используемый дважды, один раз для каждого числа. Если вы привыкли видеть оператора<'>>'>для сцепления двух парсеровДух.QiВы можете задаться вопросом, что этот<'<<'>оператор делает там? Мы решили различать генерацию и разбор последовательностей так же, как это делают библиотеки std::stream: мы используем оператор<'>>'>для ввода (парсинга) и оператор<'<<'>для вывода (генерирования). Кроме этого, существенной разницы нет. Вышеупомянутая программа создает генератор из двух более простых генераторов, склеивая их вместе с оператором последовательности. В результате получается генератор, который представляет собой композицию меньших генераторов. Белое пространство между числами может быть вставлено в зависимости от того, как используется генератор (см. ниже).

[Note]Note

Когда мы объединяем генераторы, мы получаем «большой» генератор, но это все еще генератор. Генераторы могут становиться все больше и больше, гнездясь все больше и больше, но всякий раз, когда вы склеиваете два генератора вместе, вы в конечном итоге получаете один больший генератор. Это важная концепция.

Trivial Example #3 Generating one or more numbers

Теперь создание вывода для двух чисел не слишком интересно. Давайте создадим генератор, который будет выводить нуль или больше чисел с плавающей запятой подряд.

*double_

Это как обычная звезда Клин. Мы перенесли<*>на фронт по тем же причинам, что и в.Дух.Qi: Мы должны работать с синтаксическими правилами C++. Но если вы знаете регулярные выражения (и наверняка помните эти правила синтаксиса C++), это будет выглядеть очень знакомым в течение очень короткого времени.

Любое выражение, которое оценивается генератором, может быть использовано со звездой Клин. Однако имейте в виду, что из-за правил приоритета оператора C++ вам может потребоваться поместить выражение в скобки для сложных выражений. Как и выше, белое пространство может быть вставлено неявно между генерируемыми числами, если это необходимо.

Trivial Example #4 Generating a comma-delimited list of numbers

Мы следуем примеру раздела разогреваSpirit.Qiи создадим генератор, который производит список чисел, ограниченный запятой.

double_ << *(lit(',') << double_)

Уведомление<lit(',')>. Это буквальный генератор символов, который просто генерирует запятую<','>. В этом случае звезда Клин изменяет более сложный генератор, а именно тот, который генерируется выражением:

(lit(',') << double_)

Обратите внимание, что это тот случай, когда скобки необходимы. Звезда Клин включает в себя полное выражение выше, повторяя весь шаблон в генерируемом выходе ноль или более раз.

Let's Generate!

Мы закончили с определением генератора. Осталось только вызвать генератор, чтобы он выполнил свою работу. Сейчас мы используем функцию<generate_delimited>. Одна перегрузка этой функции принимает четыре аргумента:

  1. Итератор вывода, принимающий сгенерированные символы
  2. Выражение генератора
  3. Другой генератор называется делимитирующим генератором.
  4. Данные для форматирования и вывода

Сравнивая этот минимальный пример с эквивалентным парсерным примером, мы замечаем значительную разницу. Возможно (и, на самом деле, имеет большой смысл) использовать парсер без создания какого-либо внутреннего представления парсированного ввода (т.е. без «производства» каких-либо данных из парсированного ввода). Использование парсера в этом режиме проверяет предоставленный вход на заданное выражение парсера, позволяющее проверить, является ли вход парсерным. Для генераторов этот режим не имеет никакого смысла. Что такое генерация продукции без создания какой-либо продукции? Поэтому нам всегда придется предоставлять данные, из которых должен быть получен выход. В нашем примере мы приводим список чисел<double>в качестве последнего параметра функции<generate_delimited>(см. код ниже).

В этом примере мы хотим разграничить генерируемые числа пространствами. Другой генератор, названный<space>, входит в репертуар Духа предопределенных генераторов. Это очень тривиальный генератор, который просто создает пространства. Это эквивалентно написанию<lit(' ')>или просто<' '>. Она реализована для сходства с соответствующим предопределенным<space>парсером. Мы будем использовать<space>в качестве разграничителя. Делимитер - это тот, который отвечает за вставку символов между элементами генератора, такими как<double_>и<lit>.

Хорошо, теперь давайте создадим (для полного исходного кода этого примера, пожалуйста, обратитесь кnum_list1.cpp).

template <typename OutputIterator>
bool generate_numbers(OutputIterator& sink, std::list<double> const& v)
{
    using karma::double_;
    using karma::generate_delimited;
    using ascii::space;
    bool r = generate_delimited(
        sink,                           // destination: output iterator
        double_ << *(',' << double_),   // the generator
        space,                          // the delimiter-generator
        v                               // the data to output 
    );
    return r;
}

[Note]Note

Вы можете задаться вопросом, как<vector<double>>, которая на самом деле является единой структурой данных, может использоваться в качестве аргумента (мы называем его атрибутом) для последовательности генераторов. Это кажется контринтуитивным и не соответствует вашему опыту использования<printf>, где каждый заполнитель форматирования должен быть сопоставлен с соответствующим аргументом. Ну, мы объясним это поведение более подробно позже в этом уроке. На данный момент просто рассмотрим это как особый случай, реализованный с целью обеспечения более гибкого форматирования выходных данных контейнеров STL: последовательности принимают один атрибут контейнера, если все элементы этой последовательности принимают атрибуты, совместимые с элементами, удерживаемыми этим контейнером.

Функция генерации возвращает<true>или<false>в зависимости от результата выходной генерации. Как указано в различных местах этой документации, генератор может выйти из строя по разным причинам. Одной из возможных причин является ошибка в базовом выходном итераторе (исчерпанная память или полный диск и т.д.). Другая причина может заключаться в том, что данные не соответствуют требованиям конкретного генератора.

[Note]Note

<char>и<wchar_t>операнды

Внимательный читатель может заметить, что выражение генератора имеет<','>вместо<lit(',')>, как это было в предыдущих примерах. Это хорошо благодаря синтаксическим правилам конверсии C++.<<<>, которые перегружены, чтобы принять аргумент<char>или<wchar_t>слева или справа (но не оба). Оператор может быть перегружен, если по меньшей мере один из его параметров является определяемым пользователем типом. В этом случае<double_>является 2-м аргументом<operator<<>, и поэтому используется правильная перегрузка<<<>, превращая<','>в буквальный генератор символов.

Проблема с пропуском<lit>должна быть очевидной:<'a'<< 'b'>не является генератором духа, это числовое выражение, левое смещение значения ASCII (или другого кодирующего)<'a'>на значение ASCII<'b'>. Однако оба<lit('a')<< 'b'>и<'a' <<lit('b')>являются генераторами последовательностей Духа для буквы<'a'>, за которой следует<'b'>. Рано или поздно к этому привыкнешь.

Обратите внимание, что мы включили генератор непосредственно в вызов<generate_delimited>. Называя эту функцию, выражение оценивает в временный, неназванный генератор, который передается в функцию<generate_delimited>, используется, а затем разрушается.

Здесь мы решили сделать функцию генерации общей, сделав ее шаблоном, параметризованным типом итератора вывода. При этом он может помещать сгенерированные данные в любой итератор вывода, соответствующий STL.


PrevUpHomeNext

Статья Warming up раздела Spirit 2.5.2 Tutorials может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Tutorials ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 23:11:30/0.0090980529785156/0