program options from command line initialize I'd like to receive a CR for the following command-line program options' initializing using boost::program_options. I'd like to know if there is a better way of doing this using boost::program_options or using another available library/code:

#include &lt;iostream&gt;
#include &lt;boost/program_options.hpp&gt;

using namespace std;
namespace po = boost::program_options;

int main(int ac, char* av[]) {
    /// Command line options initialize
    po::options_description visible_desc("Usage: program [options] [path/]logger_filename");
    po::options_description full_desc;
    po::positional_options_description pd;
    bool verbose, anomaly_detection, analyze_activity;
    string normal_login_word;
    string log_file_path;
    string week_start_day;

    auto generic_group = po::options_description("Generic options");
    generic_group.add_options()
            ("help,h", "produce help message")
            ("verbose", po::value&lt;bool&gt;(&amp;verbose)-&gt;default_value(false), "Show detailed times of login.")
            ;

    auto calender_group = po::options_description("Calender options");
    calender_group.add_options()
            ("week-start-day,d", po::value&lt;string&gt;(&amp;week_start_day)-&gt;default_value("Monday"), "Week starting day ('--week-start-day help' for a list).")
            ;

    auto log_group = po::options_description("Logger options");
    log_group.add_options()
            ;

    auto hidden_options_group = po::options_description("Logger options");
    hidden_options_group.add_options()
            ("log-path,l", po::value&lt;string&gt;(&amp;log_file_path)-&gt;default_value("/home/sherlock/message_from_computer"), "Path to login/logout logger.")
            ;

    auto anomalies_group = po::options_description("Mode options");
    anomalies_group.add_options()
            ("analyze-log", po::value&lt;bool&gt;(&amp;analyze_activity)-&gt;default_value(true), "Analyze activity - show activity times and summarise activity.")
            ("anomaly-detection", po::value&lt;bool&gt;(&amp;anomaly_detection)-&gt;default_value(false), "Check for anomalies in logger.")
            ("normal-login-word", po::value&lt;string&gt;(&amp;normal_login_word)-&gt;default_value("login"), "For anomaly detector- word that should symbol a login line in login/logout logger (after '+' sign).")
             ;

    pd.add("log-path", -1);

    visible_desc.add(generic_group).add(calender_group).add(log_group).add(anomalies_group);
    full_desc.add(generic_group).add(calender_group).add(log_group).add(anomalies_group).add(hidden_options_group);

    /// Command line options applying
    po::variables_map vm;
    po::store(
            po::command_line_parser(ac, av)
            .options(full_desc)
            .positional(pd)
            .run(), vm);
    po::notify(vm);

    /*
     ... Analyze options ...
    */
    return 0;
}




Update: after @pacmaninbw and @ALX23z CRs I created a new updated post: program options from command line initialize [v2 - after CR]
I tried boost::program_options but simply didn't like it.

boost::program_options has the feature that certain options are additive or hidden - which is why their usage requires so much extra work (you have to specify each option you use and state how they are processed). If you are fine without these features, you can work with config files - *.ini format - and simply read and store all option that the file has, no need for the whole mess in the main. It is not hard to implement a config file reader and Windows has built in functions for reading arguments from a .ini file.

Also this way you can supply input parameters via an .ini file instead of command line, which is much more convenient if you have more than 5 parameters and I tend to have dozens in tests.

In my case, I implemented a class ConfigFile that basically wraps a std::map&lt;string,string&gt; whose keys are in format SECTION/NAME; with added functions for getting/setting int/double/string values as well as functionality for reading a whole ini file.

In case you want to read a command line via the ConfigFile class: you can reinterpret cmd arguments and store them inside the ConfigFile class. string-based options simply store as is or optionally add a prefix-section. To support index based options you ought to provide a vector of strings to that interprets them.

I don't know of any open-source library that implements something like this, though I didn't check for any. But it is easy to implement on your own. I might publish my implementation together with a couple of other utility features as an open-source but not now. So...

Example of CMD parsing:

class CConfig
{
public:
            // sKeys is used to store index based inputs of CMD
    void ParseCMD(  int                         argc,
            const   char**                      argv,
                    std::vector&lt;std::string&gt;    sKeys = {});

   std::string  GetString(std::string key,  std::string  defaultValue);
   double       GetDouble(std::string key,  double       defaultValue);
   int          GetInt(   std::string key,  int          defaultValue);

   void         SetString(std::string key,  std::string  value);
   void         SetDouble(std::string key,  double       value);
   void         SetInt(   std::string key,  int          value);

private:
    std::mutex                          m_mutex;
    std::map&lt;std::string, std::string&gt;  m_map;
};

void CConfig::ParseCMD( int                         argc,
                const   char**                      argv,
                        std::vector&lt;std::string&gt;    sKeys)
    {
        std::lock_guard&lt;std::mutex&gt; g(m_mutex);
        size_t index = 0;
        for (int i = 1; i &lt; argc; i++)
        {
            if (argv[i][0] != '-')
            {
                if (sKeys.size() &lt;= index)
                {
                    std::cout "\n[warning]: unassigned input parameters; total number of index-based input parameters is: " &lt;&lt; sKeys.size();
                    continue;
                }

                m_map[sKeys[index]] = argv[i][0];
                continue;
            }

            if (i + 1 &lt; argc &amp;&amp; argv[i + 1][0] != '-')
            {
                m_map[argv[i]+1] = argv[i + 1];
                i++;
            }
            else
            {
                // simply defines this key with empty value
                m_map[argv[i]+1] = {};
            }
        }

        if (sKeys.size() &gt; index)
        {
            // or add option for making it into an error and not just a warning print
            std::cout &lt;&lt; "\n[warning]: not all index-based values were assigned");
        }
    }

// in main simply write:
   int main(int argc, const char* argv[])
   {
         CConfig config;
         config.ParseCMD(argc, argv, {/*list of strings for identification*/});
         ...
   }