Boost Program Options

Boost's program_options library does a lot of things (such as formatting help messages and adding default values) automatically, and it means different program modules can add and handle their own options. This is exactly what we need it for.

Its main disadvantage is incomplete documentation. There are some common command-line behaviours that aren't built in, which is fine as long as they can be added. And indeed program_options is fairly extensible and flexible, which in turn is fine as long as you have documentation to tell you how to do it.

The concern in our use case was a -v or --verbose option. GNU command line utilities often use the number of times an option recurs to increment a particular value, so -vv sets verbosity to two, -vvv to three, and so on.

The syntax for an option that expects a single integer looks like this:

boost::program_options::value<int>()

If the options is present, the final value is sent to a notifier function. By default, program_options disallows multiple occurrences of any single option from any particular source. This is sensible enough for single values, since setting them twice is at best pointless and at worse a bug (does the first or the last value count?).

Also perfectly logical is the behaviour when you want to allow multiple options:

boost::program_options::value<std::vector<int> >()

This will push the value from each new option onto the vector.

So how do we handle our incrementing option? It has to be a multiple option, because otherwise -vv would cause an error. It can't take an argument, because this would force use to write

-v true -v true or -v 1, changing the behaviour and, for the first case, being pretty redundant.

So, we could try this, using some more options from the library:

boost::program_options::value<std::vector<bool> >()
    ->zero_tokens()

As you'd expect, zero_tokens() specifies that no argument is allowed. This makes -vv acceptable. Our cunning plan is to use the size of the vector to set the verbosity level. But no! When zero_tokens() is active, nothing is added to the vector. Granted, this is sensible (what would you add?), but it would be useful if this appeared in the documentation!

We're evidently not the only ones to have encountered this problem. Since there's apparently no published solution, here's ours: accumulator.hpp. It has more or less identical syntax to boost::program_options::value, so can be used like this to increment by two for each appearance of the option:

accumulator<int>()
    ->implicit_value(2)
    ->notifier(my_func);


The final value of the option is then sent to the notifier function.

The boost program_options::value<> template additionally allows you to specify a single variable in the constructor, which is then updated with the final value. Our accumulator class currently does not support this, but it is trivial to add.

Great idea...

I had the same problem, -vv can;t be parsed. Seems like a fairly major limitation in what is otherwise a great library.

I fear I could not get your accumulator to work. I am using Boost 1.42 (its what gets loaded by default on Ubuntu 10.10).

The code I have...

po::options_description desc("Allowed options");
desc.add_options()
("help,?", "produce help message")
("verbose,v", accumulator()->implicit_value(2), "print messages")
("days,d", po::value(&days)->default_value(10), "Days to keep")
("nosaturday", "Don't keep Saturday")
("nomonth", "Don't keep first day of the month")
("test,t", "report but don't do any purges")
;

po::options_description hidden("Hidden options");
hidden.add_options()
("folder,f", po::value< vector >(), "tardis folder name")
;

po::positional_options_description p;
p.add("folder", -1);

po::options_description cmdline_options;
cmdline_options.add(desc).add(hidden);

po::variables_map vm;
po::store(po::command_line_parser(ac, av). options(cmdline_options).positional(p).run(), vm);
po::notify(vm);

I get an error when po::notify is called.

terminate called after throwing an instance of 'boost::exception_detail::clone_impl >'
what(): call to empty boost::function

Adrian Challinor
adrian dot challinor at osiris dot co dot uk

accumulator bugs

Our accumulator was written for the specific situation where a notifier function exists. Your code doesn't specify either a notifier function using ->notify() or a variable to store the accumulated value.

I don't immediately see any use for an accumulator with no target to notify, though clearly it's a shortcoming that the code crashes. An update of the header should fix this in the near future.

Neither does accumulator.hpp currently support specifying a variable in the constructor in the way that boost::program_options::value does, though it's easy to modify the code to do so.

accumulator bugs - SOLVED

Thanks for the quick response.

Understood your comments, and managed to add a custom notifier. Once I worked out how to get the value from the boost value store, I now have the accumulator working.

I think I read somewhere that the boost libraries are great, but the documentation leaves something to be desired. I would agree with that!!!

Adran