Is there a way to set an allowed set of input variables for parameters? For example parameter "arg" can have only string values like "cat" and "dog".
3 Answers
You can use the custom validator feature. Define a distinct type for your option, and then overload the validate
function on that type.
struct catdog {
catdog(std::string const& val):
value(val)
{ }
std::string value;
};
void validate(boost::any& v,
std::vector<std::string> const& values,
catdog* /* target_type */,
int)
{
using namespace boost::program_options;
// Make sure no previous assignment to 'v' was made.
validators::check_first_occurrence(v);
// Extract the first string from 'values'. If there is more than
// one string, it's an error, and exception will be thrown.
std::string const& s = validators::get_single_string(values);
if (s == "cat" || s == "dog") {
v = boost::any(catdog(s));
} else {
throw validation_error(validation_error::invalid_option_value);
}
}
The exceptions thrown from that code are no different from the exceptions thrown for any other invalid option value, so you should already be prepared to handle them.
Use the special option type instead of just string
when you define your options:
desc.add_options()
("help", "produce help message")
("arg", po::value<catdog>(), "set animal type")
;
I've composed a live example demonstrating use of this code.

- 161,384
- 21
- 275
- 467
-
This example looks very similar to the one provided in the [official documentation](http://www.boost.org/doc/libs/1_55_0/doc/html/program_options/howto.html#idp163429032). However, you need to implement an extraction operator function too `std::istream &operator>>(std::istream &in, catdog &cd)` `{` `return in >> in.value;` `}` ` – russoue Apr 29 '14 at 19:18
-
1Yes, @Russoue, my code is adapted directly from the documentation, which I linked to before. I don't know why you think the code needs stream extraction, though. I've included a working example falsifying your claim. The documentation uses `lexical_cast` to convert from the input string to the desired data type, and if you want to use that same technique, then you will indeed need to implement `operator>>`. My example uses direct construction, though. *How* to create the custom type from a string is beyond the scope of this question. – Rob Kennedy Apr 29 '14 at 20:07
-
How can I add a default value? – Åsmund Sep 19 '22 at 13:19
-
I figured it out: `("arg", po::value
()->default_value(catdog("cat"), "cat"), "set animal type")` The catdog object either needs to support ostream<< or I need to add a textual representation as the second parameter in `default_value()`. – Åsmund Sep 20 '22 at 06:17
A very simple approach is to have "animal" as a normal string and after notify you test and throw if needed.
if (vm.count("animal") && (!(animal == "cat" || animal == "dog")))
throw po::validation_error(po::validation_error::invalid_option_value, "animal");

- 688
- 6
- 16
-
-
@RobKennedy Except that Michael said "Here's what you can do", whereas jorgen said "Here's what you can do, and here's how it would look" – Nic Feb 19 '16 at 02:17
I've skimmed through the Boost.Program_options documentation, and it's not at all obvious to me whether you can do that. I get the impression that the library is primarily concerned with parsing the command line, not validating it. You might be able to work something up with a custom validator, but that involves throwing exceptions when you get bad inputs (which may be a more severe error than you want). I think that feature is more geared towards making sure you actually got a string, not that it was "cat" or "dog."
The simplest solution I can think of is to let the library parse the command-line as normal, then add your own code later to verify --arg
was set to cat
or dog
. You can then print an error and exit, revert to some suitable default, or whatever you like.

- 34,290
- 15
- 75
- 125