5

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

Community
  • 1
  • 1
volzotan
  • 4,950
  • 1
  • 14
  • 18
  • do you want to count how often `--print_status` is specified or just allow it to be added multiple times? – m.s. Jul 29 '15 at 09:39
  • just allow it to be added multiple times – volzotan Jul 29 '15 at 09:58
  • in fact, count is not that important - I am writing a pipeline-like data processing application, and I want to be able do zero-parameter processing stages (like "print_status") in between, for an arbitrary amount of times – volzotan Jul 29 '15 at 09:59

1 Answers1

5

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.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    The first example worked for me with a little modification: `po::value >() ->default_value(std::vector(), "false") ->implicit_value(std::vector(1), "true") ->zero_tokens()` – gufftan Jul 30 '15 at 06:52