What's an effective way to parse command line parameters in C++?

前端 未结 6 2050
滥情空心
滥情空心 2021-02-09 05:46

Is there a really effective way of dealing with command line parameters in C++?

What I\'m doing below feels completely amateurish, and I can\'t imagine this is how comma

6条回答
  •  庸人自扰
    2021-02-09 06:25

    It's a bit too big to include in a Stack Overflow answer, but I made a library for defining commands lines declaratively. It takes advantage of the the C++14 ability to build up a class constructor by giving initial values to each member variable.

    The library is mostly a base class. To define your command syntax, you declare a struct that derives from it. Here's a sample:

    struct MyCommandLine : public core::CommandLine {
        Argument m_verb{this, "program", "program.exe",
            "this is what my program does"};
        Option m_help{this, "help", false,
            "displays information about the command line"};
        Alias alias_help{this, '?', &m_help};
        Option m_demo{this, "demo", false,
            "runs my program in demonstration mode"};
        Option m_maximize{this, "maximize", false,
            "opens the main window maximized"};
        Option m_loops{this, "loops", 1,
            "specifies the number of times to repeat"};
        EnumOption m_size{this, "size", 3,
                               { {"s", 1},
                                 {"small", 1},
                                 {"m", 3},
                                 {"med", 3},
                                 {"medium", 3},
                                 {"l", 5},
                                 {"large", 5} } };
        BeginOptionalArguments here{this};
        Argument m_file{this, "file-name", "",
            "name of an existing file to open"};
    } cl;
    

    The Argument, Option, and Alias class templates are declared in the scope of the CommandLine base class, and you can specialize them for your own types. Each one takes the this pointer, the option name, the default value, and a description for use in printing the command synopsis/usage.

    I'm still looking to eliminate the need to sprinkle all the this pointers in there, but I haven't found a way to do it without introducing macros. Those pointers allow each member to register itself with the tables in the base class that drive the parsing.

    Once you have an instance, there are several overloads of a method to parse the input from a string or a main-style argument vector. The parser handles both Windows-style and Unix-style option syntax.

    if (!cl.Parse(argc, argv)) {
        std::string message;
        for (const auto &error : cl.GetErrors()) {
            message += error + "\n";
        }
        std::cerr << message;
        exit(EXIT_FAILURE);
    }
    

    Once it's parsed, you can access the value of any of the options using operator():

    if (cl.m_help()) { std::cout << cl.GetUsage(); }
    for (int i = 0; i < cl.m_loops(); ++i) { ... }
    

    The whole library is only about 300 lines (excluding tests). The instances are a bit bloaty, since the parsing tables are part of the instance (rather than the class). But you generally only need one instance per program, and the convenience of this purely declarative approach is pretty powerful, and an instance can be reset simply by parsing new input.

提交回复
热议问题