I am wondering whether it is possible to use zero-parameter options multiple times with boost::program_options.
I have something in mind like this:
mytool --load myfile --print_status --do-something 23 --print_status
It is easy to get this working with one "print_status" parameter, but it is not obvious to me how one could use this option two times (in my case, boost throws an exception if a zero-parameter option is specified more than once).
So, the question is:
Is there any (simple) way to achieve this with out-of-the box functionality from program_options?
Right now, it seems this is a drawback of the current program_options implementation.
P.S.:
There have already been similar questions in the past (both over four years old), where no solution was found:
http://lists.boost.org/boost-users/2006/08/21631.php
http://benjaminwolsey.de/de/node/103
This thread contains a solution, but it is not obvious whether it is a working one, and it seems rather complex for such a simple feature:
Specifying levels (e.g. --verbose) using Boost program_options
If you don't need to count the number of times the option has been specified, it's fairly easy (if a little odd); just declare the variable as vector<bool>
and set the following parameters:
std::vector<bool> example;
// ...
desc.add_options()
("example,e",
po::value(&example)
->default_value(std::vector<bool>(), "false")
->implicit_value(std::vector<bool>(1), "true")
->zero_tokens()
)
// ...
Specifying a vector
suppresses multiple argument checking; default_value
says that the vector should by default be empty, implicit_value
says to set it to a 1-element vector if -e/--example
is specified, and zero_tokens
says not to consume any following tokens.
If -e
or --example
is specified at least once, example.size()
will be exactly 1
; otherwise it will be 0
.
Example.
If you do want to count how many times the option occurs, it's easy enough to write a custom type and validator:
struct counter { int count = 0; };
void validate(boost::any& v, std::vector<std::string> const& xs, counter*, long)
{
if (v.empty()) v = counter{1};
else ++boost::any_cast<counter&>(v).count;
}
Example.
Note that unlike in the linked question this doesn't allow additionally specifying a value (e.g. --verbose 6
) - if you want to do something that complex you would need to write a custom value_semantic
subclass, as it's not supported by Boost's existing semantics.