Conar 2: классы за борт!

Начало

Вторая «серия» планировалась через два дня после первой. Получилось — через две недели. Лень-матушка вперёд нас родилась…

Синтаксис вызова парсера

Предложенный ранее синтаксис для Parser несколько избыточен по части скобок :)

Новый синтаксис:

auto parser = parse(опция_1, опция_2, ...);
auto unparsed = parser(argc, argv);
cout << parser.help(...) << endl;

С помощью шаблона с переменным числом параметров данный синтаксис легко добавить к тому, что уже есть:

namespace impl
{
  /// A stub for parse with more parameters.
  inline void parse(Parser&) {}

  /// Add all options to the parser in one recursive call.
  template <class Opt1, class... Other> inline
  void parse(Parser &parser, Opt1 &&option_1,
               Other&&... other_options)
  {
    parser(forward<Opt1>(option_1));
    parse(parser, forward<Other>(other_options)...);
  }
}

/// Make a parser with all options in one call.
template <class... Options>
Parser parse(Options&&... options)
{
  Parser parser;
  impl::parse(parser, forward<Options>(options)...);
  return parser;
}

Представление опций

Объединение общего описания possible_keys и info (фактически, это DTO) с типозависимым поведением (handler) не есть хорошо. Можно было бы сделать из Option чисто абстрактный класс («интерфейс»), наследники которого определяли бы вызов обработчика (handler) и, вероятно, распознавание текста (собственно параметров) — пара виртуальных функций.

Но зачем парсеру знать эти подробности? Фактически, с точки зрения парсера всё поведение «опции» сконцентрировано в одном действии — распознавании текста. Какие там в процессе значения получаются, и как они затем обрабатываются, парсеру всё равно. Поэтому соблазнительно определить это одним замыканием (функциональным объектом), который «скармливается» парсеру. Надо только придумать интерфейс вызова…

Представим, что парсер распознал ключ. То, что после ключа может быть параметром (параметрами) соответствующей ключу опции. Как их передать и как понять, что было успешно принято (распознано)?

Вариант ключа 1, ключ t, time

-t5, --time=5 — только одно значение может быть параметром — то, что идёт сразу за ключом или после знака =. Это часть («хвост») аргумента командной строки. Все прочие аргументы к делу не относятся.

Вариант ключа 2, ключ times

--times 10 start 20 finish — произвольное число параметров — аргументы командной строки за аргументом, содержащим ключ, и до конца или следующего аргумента, содержащего ключ.

Вариант ключа 1 можно рассматривать как частный случай варианта ключа 2. Для разбора в какой-то форме можно передавать массив строк. А возвращать, например, количество успешно распознанных строк. Но как сообщать другие ошибки: неверный формат, недостаточное количество параметров? В конце концов, этот вопрос можно отдать на откуп обработчику, а не решать его на уровне парсера.

Итого, получаем STL-подобный интерфейс:

template <class FwdIt>
FwdIt option_parse(FwdIt from, FwdIt to);
// iterator_traits<FwdIt>::value_type = string

Статическая проверка на соответствие сигнатуры вызова предполагаемого обработчика распознанных значений ключа может выполняться с помощью следующих определений (упакованы в namespace impl):

template <class FlagHandler>
using Is_flag_handler = std::is_convertible<
	FlagHandler, std::function<void()>>;

template <class ValueHandler, class T>
using Is_value_handler_for = std::is_convertible<
	ValueHandler, std::function<void(T)>>;

template <class SeqHandler, class T>
using Is_seq_handler_for = std::is_convertible<
	SeqHandler, std::function<void(T*, T*)>>;

Код данного варианта целиком.

Продолжение следует.

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: