Processing optional parameters in the main

Suppose I have a main function that basically just calls one other function as an entry point into the program. A function (and, therefore, a complete program) has a number of mandatory and several optional parameters:

#include <iostream>
#include <sstream>

void function_to_call(std::string arg1,
                  std::string arg2,
                  std::string arg3,
                  std::string arg4,
                  std::string arg5 = "foo",
                  std::string arg6 = "bar",
                  int num1 = 1,
                  int num2 = 2
                  )

{
  // do fancy stuff here                                                                                                                                                                                                                                                                                                
}


int main(int argc, char** argv)
{

  int num1, num2;

  std::stringstream stream;

  if( argc < 5 ) {
    std::cerr << "Usage: \n\t" << argv[0]
              << "\n\t\t1st argument"
              << "\n\t\t2nd argument"
              << "\n\t\t3rd argument"
              << "\n\t\t4th argument"
              << "\n\t\t5th argument (optional)"
              << "\n\t\t6th argument (optional)"
              << "\n\t\t7th argument (optional)"
              << "\n\t\t8th argument (optional)"
              << "\n\t\t9th argument (optional)" << std::endl;
  }
  if( argc == 5 ) {
    function_to_call( argv[1], argv[2], argv[3], argv[4] );
  }
  if( argc == 6 ) {
    function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5] );
  }
  if( argc == 7 ) {
    function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6] );
  }
  if( argc == 8 ) {
    stream << argv[7];
    stream >> num1;
    function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], num1 );
  }
  if( argc == 9 ) {
    stream << argv[7] << ' ' << argv[8];
    stream >> num1 >> num2;
    function_to_call( argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], num1, num2 );
  }

  return 0;

}

The chain ifcan be replaced by switch, the command line can be slightly matched using a library getoptor boost program_options, but this does not actually change things conceptually.

Is there an obvious way that I cannot handle different amounts of parameters?

+4
source share
4 answers

, () , , . ( ):

class Base
{
public:
  virtual void set(const char *) = 0;
};

class Int : public Base {
public:
  Int(int value) : value_(value) {}
  Int(const char* value) : value_(std::stoi(value)) {}
  virtual void set(const char* value) { value_ = std::stoi(value); }
  int get() { return value_; }
private:
  int value_;
};

class Str : public Base {
public:
  Str(const char* value): value_(value) {}
  virtual void set(const char* value) { value_ = value; }
  std::string get() { return value_; }
private:
  std::string value_;
};

: , ,

int main(int argc, char** argv)
{

  std::vector<Base*> theopts = { new Str(""),new Str(""),new Str(""),new Str(""),new Str("foo"),new Str("bar"),new Int(1),new Int(2) };

  if( argc < 5 ) {
     // put meaningful handling here
  }

  for( int i = 0; i < argc-1; ++i ) {
    theopts[i]->set(argv[i+1]);
  }

  function_to_call( static_cast<Str*>(theopts[0])->get(),
                    static_cast<Str*>(theopts[1])->get(),
                    static_cast<Str*>(theopts[2])->get(),
                    static_cast<Str*>(theopts[3])->get(),
                    static_cast<Str*>(theopts[4])->get(),
                    static_cast<Str*>(theopts[5])->get(),
                    static_cast<Int*>(theopts[6])->get(),
                    static_cast<Int*>(theopts[7])->get()
                    );
}

, , - , if .

0

, , :

void function_to_call(std::string arg1,
                  std::string arg2,
                  std::string arg3,
                  int num1,
                  int num2
                  )

{
  // do fancy stuff here
    std::cout << "arg1: " << arg1 << '\n';
    std::cout << "arg2: " << arg2 << '\n';
    std::cout << "arg3: " << arg3 << '\n';
    std::cout << "num1: " << num1 << '\n';
    std::cout << "num2: " << num2 << '\n';
}

struct config
{
    std::string arg1;
    std::string arg2;
    std::string arg3 = "wibble"; // set arg3 default here
    int arg4 = 1;                // set arg4 default here
    int arg5 = 0;                // set arg5 default here
};

config parse_command_params(char** argv)
{
    config cfg;

    if(!argv[1])
        throw std::runtime_error("At least 2 args required");

    cfg.arg1 = argv[1];

    if(!argv[2])
        throw std::runtime_error("At least 2 args required");

    cfg.arg2 = argv[2];

    // optional from here on

    if(!argv[3])
        return cfg;

    cfg.arg3 = argv[3];

    if(!argv[4])
        return cfg;

    cfg.arg4 = std::stoi(argv[4]);

    if(!argv[5])
        return cfg;

    cfg.arg5 = std::stoi(argv[5]);

    return cfg;
}

int main(int, char** argv)
{
    try
    {
        config cfg = parse_command_params(argv);

        function_to_call(cfg.arg1, cfg.arg2, cfg.arg3, cfg.arg4, cfg.arg5);
    }
    catch(std::exception const& e)
    {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

struct, , , .

. , @cmaster .

+3

- , . , , . , function_to_call, if-elseif . , . , std:: stringstream. , , Boost function_to_call. , function_to_call , , .

+2

, , , - . , . , , DefineRequiredArgs DefineOptionalArgs, .

// multi_option_helper.cpp

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

void function_to_call(std::vector<std::vector<std::string> > &req_args,
                      std::vector<std::vector<std::string> > &opt_args,
                      int num1 = 1,
                      int num2 = 2
                      )

{
    // do fancy stuff here

    // Print required options
    std::cout << "Required Options:\n" ;
    for (int i=0; i<req_args.size(); i++) {
        std::cout << "\t" << req_args[i][0] << " = " << req_args[i][1] << std::endl;
    }
    // Print optional options
    std::cout << "Optional Options:\n" ;
    for (int i=0; i<opt_args.size(); i++) {
        std::cout << "\t" << opt_args[i][0] << " = " << opt_args[i][1] << std::endl;
    }

}

std::vector<std::vector<std::string> > DefineRequiredArgs()
{
    // Define the required arguments
    std::vector<std::vector<std::string> > req_args ;

    /* pre-c++11 way of doing it */
    // Define a generic vector of strings
    std::vector<std::string> arg(2) ;
    arg[1] = "" ;
    arg[0] = "1st_argument" ;
    req_args.push_back(arg) ;
    arg[0] = "2nd_argument" ;
    req_args.push_back(arg) ;
    arg[0] = "3rd_argument" ;
    req_args.push_back(arg) ;
    arg[0] = "4th_argument" ;
    req_args.push_back(arg) ;
    // ... continue this process as many times as needed

    /* post-c++11 way of doing it
     req_args.push_back({"1st_argument", ""}) ;
     req_args.push_back({"2nd_argument", ""}) ;
     req_args.push_back({"3rd_argument", ""}) ;
     req_args.push_back({"4th_argument", ""}) ;
     */

    return req_args ;
}

std::vector<std::vector<std::string> > DefineOptionalArgs()
{
    // Define the required arguments
    std::vector<std::vector<std::string> > opt_args ;

    // pre-c++11
    std::vector<std::string> arg(2) ;
    arg[1] = "" ;
    arg[0] = "5th_argument" ;
    arg[1] = "foo" ;
    opt_args.push_back(arg) ;
    arg[0] = "6th_argument" ;
    arg[1] = "bar" ;
    opt_args.push_back(arg) ;
    arg[0] = "7th_argument" ;
    arg[1] = "521600" ;
    opt_args.push_back(arg) ;
    arg[0] = "8th_argument" ;
    arg[1] = "86" ;
    opt_args.push_back(arg) ;
    arg[0] = "9th_argument" ;
    arg[1] = "somethingelse" ;
    opt_args.push_back(arg) ;
    // ... continue this process as many times as needed

    /* c++11 alternative
     opt_args.push_back({"5th_argument", "foo"}) ;
     opt_args.push_back({"6th_argument", "bar"}) ;
     opt_args.push_back({"7th_argument", "521600"}) ;
     opt_args.push_back({"8th_argument", "86"}) ;
     opt_args.push_back({"9th_argument", "somethingelse"}) ;
     */

    return opt_args ;
}

int main(int argc, char** argv)
{
    // Get the required options
    std::vector<std::vector<std::string> > req_args = DefineRequiredArgs() ;
    // Get the optionsl options
    std::vector<std::vector<std::string> > opt_args = DefineOptionalArgs() ;

    if( argc < req_args.size()+1 ) {
        std::cerr << "Usage: \n\t" << argv[0] ;
        // Print the required arguments
        for (int i=0; i<req_args.size(); i++) {
            std::cerr << "\n\t" << req_args[i][0] ;
        }
        // Print the optional arguments
        for (int i=0; i<req_args.size(); i++) {
            std::cerr << "\n\t" << opt_args[i][0]
            << " (optional Default=" << opt_args[i][1] << ")" ;
        }
        std::cerr << std::endl;
    } else {
        // Fill the required options
        int opt_counter(1) ;
        while ((opt_counter <= req_args.size())) {
            req_args[opt_counter-1][1] = std::string(argv[opt_counter]) ;
            opt_counter++ ;
        }
        // Now fill the optional options
        int offset(req_args.size()+1) ; // Note the additional offset of '1'
        while ((opt_counter < argc)) {
            opt_args[opt_counter-offset][1] = std::string(argv[opt_counter]) ;
            opt_counter++ ;
        }
        // Fill num1 and num2
        int num1, num2 ;
        std::stringstream stream ;
        stream << opt_args[2][1] << ' ' << opt_args[3][1] ;
        stream >> num1 >> num2 ;

        /* c++11 alternative
        int num1 = std::stoi(opt_args[2][1]) ;
        int num2 = std::stoi(opt_args[3][1]) ;
        */
        // Now call the helper function
        function_to_call(req_args, opt_args, num1, num2) ;
    }

    return 0;
}

, , , :

Usage: 
    ./multi_option_helper
    1st_argument
    2nd_argument
    3rd_argument
    4th_argument
    5th_argument (optional Default=foo)
    7th_argument (optional Default=521600)
    8th_argument (optional Default=86)
    9th_argument (optional Default=somethingelse)

, "++", "++ 11", , g++ multi_option_helper.cpp -o multi_option_helper, ++ 11, ,

, , , , (, --Arg1=arg1_val), "GetOpt". . ( -h --help ).

: BOOST, . ( , BOOST , ), , , . GetOpt, , , . , . , .

0

Source: https://habr.com/ru/post/1654929/


All Articles