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
--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:
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:
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.