peteris.rocks

Boost program_options order of arguments

How to get arguments in order

Last updated on

Problem

Normally when you use boost's program_options the order of arguments is not available.

#include <boost/program_options.hpp>

using namespace boost::program_options;

int main(int argc, char** argv) {
  options_description options_filters("Filters");
  options_filters.add_options()
    ("lowercase", "Lowercase line")
    ("uppercase", "Uppercase line")
    ("max-length", value<int>(), "Remove lines that are longer than this");

  variables_map vm;
  store(parse_command_line(argc, argv, options_filters), vm);
  notify(vm);

  for (auto &opt : vm) {
    cout << opt.first << endl;
  }
}

So running

./app --lowercase --max-length=5

might end up printing

max-length
lowercase

because vm is an std::map and the order of items is not preserved.

Solution

It turns out that parse_command_line returns an object which contains a vector of all arguments in order.

auto parsed = parse_command_line(argc, argv, options_filters);

for (auto &opt : parsed.options) {
  cout << opt.string_key << endl;
}

Example

#include <iostream>
#include <iterator>

#include <boost/program_options.hpp>

using namespace std;
using namespace boost;
using namespace boost::program_options;

int main(int argc, char** argv) {
  try {

    options_description options_filters("Filters");
    options_filters.add_options()
      ("lowercase", "Lowercase line")
      ("uppercase", "Uppercase line")
      ("max-length", value<int>()->notifier([](int arg) { cout << "Max=" << arg << endl }),
        "Remove lines that are longer than this");

    cout << options_filters << endl;

    variables_map vm;
    auto parsed = parse_command_line(argc, argv, options_filters);
    store(parsed, vm);
    notify(vm);

    for (auto &x : parsed.options) {
      cout << x.string_key << endl;
      filters.push_back(x.string_key);
      auto opt = options_all.find(x.string_key, false).semantic();
      opt->notify(vm[x.string_key].value());
    }

    for (auto &f : filters) {
      cout << f << endl;
    }

    return 0;
  } catch (std::exception& e) {
    cerr << "error: " << e.what() << endl;
    return 1;
  } catch (...) {
    cerr << "Exception of unknown type!" << endl;
    return 1;
  }
}