Boost program_options: 允许未声明的环境

Boost program_options: allow undeclared from environment

我有一个分两步加载选项的应用程序。在第二步中,某些选项可能未在 options_description 对象中声明(取决于第一步中传递的选项)。

似乎没有忽略未声明的选项,类似于解析command line arguments and configuration files

一个最小的工作示例:

#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)

旁注

还有一件烦人的事情——如果我不声明 "opt1" 而声明 "OPT1",它甚至不会识别 MYAPP_OPT1!

恕我直言,这将是对 boost 库的一个很好的补充,使其与命令行和配置文件解析器保持一致。

以下改编自my gist.


当使用 Boost 的 program_options 加载环境变量时,无法告诉 boost 忽略那些未在 options_description 对象中指定的变量。

此代码段展示了如何获得与可用于命令行和配置文件解析器的 allow_unregistered() 选项类似的行为。

例如,如果您尝试通过指定名为 one 的选项并在 parse_environment 中使用前缀 MYAPP 来读取 MYAPP_ONE,它将正常工作。

如果 options_description 对象中没有包含另一个 MYAPP_X,就会出现问题。然后会抛出异常。

如果您使用程序参数(argcargv)或配置文件,库中有一个选项可以简单地忽略未在 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);