2012-10-06 15 views
8

que estoy usando program_options impulsar 1.50.0Quiere permitir que las opciones se especifiquen varias veces cuando se usan las opciones del programa boost. En este momento tengo varias apariciones

Quiero permitir lo siguiente para mi programa foobar foobar --debug 2 --debug 3

A partir del código program_options impulso, hay un ejemplo que regex.cpp muestra la creación de un nuevo tipo y la creación de un validador para ese tipo.
lo he intentado, y funciona, pero ahora no puede utilizar algunos de los demás add_options() typed_value opciones, como default_value, composición, etc.

Aquí es lo que he intentado hasta ahora:

#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; 
} 

Así que si lo hago: foobar --debug 2 3 --debug

Si comento hacia fuera la opción de depuración actual ....

("debug", value<lastmultioccurrenceint>(), "debug value (0-4), default is 0 (performance mode)") 

... y elimine el comentario de las dos líneas siguientes:

lastmultioccurrenceint debugOpt; 
("debug", value<lastmultioccurrenceint>(&debugOpt)->default_value(0)->composing(), "debug value (0-4), default is 0 (performance mode)") 

... entonces no incluso de compilación.

¿Sabes cómo hacer esto para que me permita usar default_value y componer? Podría estar heredando de typed_value, pero no he encontrado una buena manera de hacerlo todavía.

+0

no es claro para mí lo que estamos tratando de lograr. La biblioteca admite fácilmente lo que parece ser su sintaxis deseada 'foobar --debug 2 --debug 3' con un' std :: vector 'como tipo de opción. –

+0

Quiero la segunda opción para anular la primera opción. Entonces, en su ejemplo, establecería la opción de depuración en 3. –

Respuesta

5

No creo que necesite definir un tipo personalizado con un validador para lograr el resultado deseado. Se puede hacer con el soporte de información semántica existente de la biblioteca. Considere este ejemplo

#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; 
    } 
} 

y muestra de uso:

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$ 
+0

Veo su punto, pero quiero poder acceder a la opción de depuración como un entero en todo el programa. –

+0

Por ejemplo: 'template T CCommandLineArgs :: GetOption (const string & strOption) const' es una función que uso para acceder a todos los argumentos de línea de comandos. Tengo varios lugares en mi programa donde llamo 'GetOption (" debug ")'. Me gustaría mantener este tipo de interfaz para todas las opciones de línea de comandos. –

+0

Dentro de "GetOption" No deseo tener un código especial para determinadas opciones. Supongo que podría simplemente mirar el tipo DebugValues ​​y hacer lo que sugiera cada vez que sea el tipo de datos utilizados ... –

Cuestiones relacionadas