C++ - Simple command line argument manager

Command-line argument management is tricky to get right especially when the number of options that we support and the number of their combination is big. For this kind of applications, there are already a number of very effective libraries and tools supporting the programming in such a scenario. One such library is Boost::program_options which I highly encourage you to use as is it awesome.

But there are other cases where we need to quickly write a prototype or when the number of options and possible configuration is small where using Boost could be overkill. In such cases what we usually do is writing ad-hoc command-line options management code which will never be reuse and it is tailored for the specific application at hand. This approach costs time and it is boring once you did it once.

For this reason, I wrote a super simple and minimalistic C++17 command-line argument manager which allows you to:

  • Check if a set of options has been specified
  • Get the argument of each element of a set of options (as string).

The class is extremely easy to use. You only need to construct an instance of the class by passing the argc and argv variables and then you are ready to go. No more need for ugly and error prone command line argument parsing. For instance, as you can see from the code snippet below, I check for the existence of the -h or --help options and of all the other required options. If one of -X, -O, -P are not present or its required corresponding argument are not specified a help message is printed. Otherwise, the arguments are retrieved and returned as a vector of strings ready to be used.

The example code is listed below or can be downloaded from here (gist on GitHub). You can also try it live on wandbox.

#include <string>
#include <algorithm>
#include <vector>
#include <tuple>
#include <iostream>
#include <optional>


void usage(const std::string&amp; progName) {
  std::cout << progName << " -X FILE -P FILE -O DIRECTORY " << std::endl
            << "Options:"                        << std::endl
            << "-h  | --help    Print this help" << std::endl
            << "-X              Path to X file"  << std::endl
            << "-P              Path to P file"  << std::endl
            << "-O              Path to output directory." << std::endl;
}

class cmdline_args_parser{
    public:
        cmdline_args_parser (const int argc, char **argv){
            for (int i=0; i < argc; ++i)
                tokens.push_back(std::string(argv[i]));          
        }

        const std::optional<std::string> getCmdOption(const std::string &amp;option) const{
            auto  itr =  std::find(tokens.begin(), tokens.end(), option);
            if (itr != tokens.end() &amp;&amp; ++itr != tokens.end())
                return std::optional(*(itr));           
           return std::nullopt;
        }
    
        template<typename... Options>
        const auto get_all_options(const Options... ops) const{
            std::vector<std::optional<std::string>> v;
            (v.push_back(getCmdOption(ops)), ...);
            return v;
        }

        bool cmdOptionExists(const std::string &amp;option) const{
            return 
                std::find(tokens.begin(), tokens.end(), option) != tokens.end();
        }
 
        template<typename... Options>
        bool all_options_exists(const Options... opts) const{
            return (... &amp;&amp; cmdOptionExists(opts)); 
        }
        template<typename... Options>
        bool any_options_exists(const Options... opts) const{
            return (... || cmdOptionExists(opts)); 
        }
    
        const std::string&amp; get_program_name() const{ return tokens[0]; }
    
    private:
        std::vector<std::string> tokens;
};


auto process_args(const cmdline_args_parser&amp; p){
    auto opts = p.get_all_options("-X","-O","-P");
    if(p.any_options_exists("-h", "--help") || 
       !all_of(begin(opts), end(opts), [](const  auto&amp; x ){return x;}) )
    {
        usage(p.get_program_name());
        return;
    }
    for(const auto opt : opts){
        std::cout<<opt.value()<<std::endl;
    }
}

int main(int argc, char** argv){
cmdline_args_parser p (argc, argv);
process_args(p);    

  return 0;
}
Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *