Boost program_options: разрешить необъявленное из среды - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть приложение, которое загружает опции в два этапа.На втором шаге некоторые параметры могут быть необъявленными в объекте options_description (в зависимости от того, какие параметры были переданы на первом шаге).

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

Минимальный рабочий пример:

#include <boost/program_options.hpp>

namespace po = boost::program_options;

int main() {
  int opt1;

  po::options_description options("my app options");
  options.add_options()
    ("opt1", po::value<int>(&opt1)->default_value(0), "option 1");

  po::variables_map env;
  po::store(po::parse_environment(options, "MYAPP_"), env);
  po::notify(env);

  printf("opt1: %d\n", opt1);
  return 0;
}

По умолчанию вы получите значениенуля, как и ожидалось:

$ ./a.out
opt1: 0

Если вы установите MYAPP_OPT1, он также будет работать как положено

$ MYAPP_OPT1=123 ./a.out
opt1: 123

Однако, если вы установите переменную, которая не указана в конфигурациифайл, он вылетит.

$ MYAPP_UNDEFINED=456 ./a.out
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::unknown_option> >'
  what():  unrecognised option
Aborted (core dumped)

Sidenote

Есть и другая раздражающая вещь - если вместо объявления "opt1" я объявлю "OPT1", он даже не будетраспознать MYAPP_OPT1!

1 Ответ

0 голосов
/ 13 ноября 2018

ИМХО, это было бы хорошим дополнением к библиотеке буста, сделав его наравне с парсерами командной строки и файла конфигурации.

Следующее адаптировано из my gist .


При использовании программных_опций Boost для загрузки переменных окружения нельзя сказать, чтобы boost игнорировал те, которые не были указаны в объекте options_description.

В этом фрагменте показано, какчтобы получить поведение, аналогичное параметру allow_unregistered(), доступному для парсера командной строки и файла конфигурации.

Например, если вы попытаетесь прочитать MYAPP_ONE, указав параметр с именем one и используя префикс MYAPPв parse_environment все будет работать нормально.

Проблема возникает, если есть еще один MYAPP_X, который не был включен в объект options_description.Тогда будет выдано исключение.

Если вы используете аргументы программы (argc, argv) или файл конфигурации, в библиотеке есть опция, позволяющая просто игнорировать опции, которые не были объявленыв options_description.

Для переменных окружения это не так.Этот фрагмент будет просто читать объявленные вами параметры и игнорировать любые другие, которые могли быть объявлены.

Таким образом, он ведет себя как функциональность allow_unregistered().

po::options_description options("My Options");
lib_options.add_options()
  (
    "MY_VAR",
    po::value<bool>(&my_var)->default_value(false),
    "Dummy boolean test"
  )
;

po::variables_map env;
po::store(po::parse_environment(
  options,
  [options](const std::string& var) {
    return std::any_of(
      options.options().cbegin(),
      options.options().cend(),
      [var](auto opt) { return var == opt->long_name(); }) ? var : "";
}), env);
po::notify(env);
...