I am using boost program_options 1.50.0
I want to ALLOW the following for my program foobar
foobar --debug 2 --debug 3
From the boost program_options code, there is an example regex.cpp that shows creating a new type and creating a validator for that type.
I tried that, and it works, but now I cannot use some of the other add_options() typed_value options, like default_value, composing, etc.
Here is what I tried so far:
#include <boost/program_options.hpp>
using namespace boost;
using namespace boost::program_options;
#include <iostream>
using namespace std;
struct lastmultioccurrenceint {
public:
lastmultioccurrenceint(int n) : n(n) {}
int n;
};
void validate(boost::any& v,
const std::vector< std::string >& xs,
//const std::vector< std::basic_string<charT> >& xs,
lastmultioccurrenceint* , int)
{
using namespace boost::program_options;
cerr << "IN VALIDATE" << endl;
//validators::check_first_occurrence(v);
string s = validators::get_single_string(xs);
if (!v.empty()) {
cerr << "\tPRINTTING MULTIOCCURENCE WARNING, allowing v to be overwritten" << endl;
cerr << "\tEarlier value was: " << boost::any_cast<int>(v) << endl;
cerr << "\tNew value is: " << s << endl;
}
try {
//v = any(lastmultioccurrenceint(lexical_cast<int>(sx)));
//v = any(lexical_cast<int>(sx)); // works
v = any(lexical_cast<int>(s));
//v = any(lexical_cast<lastmultioccurrenceint>(s));
//v = any(4);
//}
/*catch(const bad_lexical_cast&) {
boost::throw_exception(validation_error::invalid_option_value(s));
} */
}
catch(const bad_lexical_cast&) {
throw validation_error(validation_error::invalid_option_value);
}
cerr << "made it through" << endl;
int main (int argc, char **argv) {
variables_map m_varMap;
// define style
// unix_style = (allow_short | short_allow_adjacent | short_allow_next
// | allow_long | long_allow_adjacent | long_allow_next
// | allow_sticky | allow_guessing
// | allow_dash_for_short),
// ... allows typical unix-style options
// allow_long_disguise = can use "-" instead of "--"
// Reference: http://www.boost.org/doc/libs/1_42_0/doc/html/boost/program_options/command_line_style/style_t.html
//
try {
ProgOpts::command_line_style::style_t style = ProgOpts::command_line_style::style_t(
ProgOpts::command_line_style::unix_style |
//ProgOpts::command_line_style::case_insensitive |
ProgOpts::command_line_style::allow_long_disguise );
options_description options("YDD");
//lastmultioccurrenceint debugOpt;
options.add_options()
("debug", value<lastmultioccurrenceint>(), "debug value (0-4), default is 0 (performance mode)")
//("debug", value<lastmultioccurrenceint>(&debugOpt)->default_value(0)->composing(), "debug value (0-4), default is 0 (performance mode)")
;
//ProgOpts::parsed_options firstPreParsed = ProgOpts::command_line_parser(argc,argv).options(options).style(style).allow_unregistered().run();
ProgOpts::parsed_options firstPreParsed = ProgOpts::command_line_parser(argc,argv).options(options).allow_unregistered().run();
ProgOpts::store(firstPreParsed, m_varMap);
ProgOpts::notify(m_varMap);
}
/*catch (boost::program_options::multiple_occurrences &e) {
cerr << "GOT MULTIPLES" << endl;
cerr << "Option Name: " << e.get_option_name() << endl;
cerr << e.what() << endl;
}
catch(boost::bad_any_cast& e) {
cerr << "WRONG TYPE" << endl;
cerr << e.what() << endl;
} */
catch(std::exception& e) {
cerr << "SOMETHING ELSE" << endl;
cerr << e.what() << endl;
}
catch(...) {
cerr << "UNKNOWN ERROR" << endl;
}
cerr << "DEBUG OPT IS: " << m_varMap["debug"].as<int>() << endl;
}
So if I do: foobar --debug 2 --debug 3
If I comment out the current debug option ....
("debug", value<lastmultioccurrenceint>(), "debug value (0-4), default is 0 (performance mode)")
... and uncomment out the following two lines:
lastmultioccurrenceint debugOpt;
("debug", value<lastmultioccurrenceint>(&debugOpt)->default_value(0)->composing(), "debug value (0-4), default is 0 (performance mode)")
... then it doesn't even compile.
Do you know how to do this so that it allows me to use default_value and composing? It might be inheriting from typed_value, but I haven't found a good way to do this yet.
I don't think you need to define a custom type with a validator to achieve the desired result. It can be done with the existing semantic information support of the library. Consider this example
#include <boost/assign/list_of.hpp>
#include <boost/program_options.hpp>
#include <boost/version.hpp>
#include <iostream>
int
main( int argc, char** argv )
{
namespace po = boost::program_options;
po::options_description desc("Options");
typedef std::vector<unsigned> DebugValues;
DebugValues debug;
desc.add_options()
("help,h", "produce help message")
("debug", po::value<DebugValues>(&debug)->default_value(boost::assign::list_of(0), "0")->composing(), "set debug level")
;
po::variables_map vm;
try {
const po::positional_options_description p; // note empty positional options
po::store(
po::command_line_parser( argc, argv).
options( desc ).
positional( p ).
run(),
vm
);
po::notify( vm );
if ( vm.count("help") ) {
std::cout << desc << "\n";
std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;
return 0;
}
} catch ( const boost::program_options::error& e ) {
std::cerr << e.what() << std::endl;
}
std::cout << "got " << debug.size() << " debug values" << std::endl;
if ( !debug.empty() ) {
DebugValues::const_iterator value( debug.end() );
std::advance( value, -1 );
std::cout << "using last value of " << *value << std::endl;
}
}
and sample usage:
samm$ ./a.out -h
Options:
-h [ --help ] produce help message
--debug arg (=0) set debug level
boost version: 1_46_1
samm$ ./a.out --debug 1 --debug 2
got 2 debug values
using last value of 2
samm$ ./a.out --debug 4 --debug 1
got 2 debug values
using last value of 1
samm$ ./a.out --debug 4 --debug 1 --debug 9
got 3 debug values
using last value of 9
samm$
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With