p-ranav / argparse

Argument Parser for Modern C++
MIT License
2.72k stars 250 forks source link

Support boolean argument with the form like '--enable-hack=true/false' #313

Open rtgiskard opened 12 months ago

rtgiskard commented 12 months ago

This explicit switch can be useful when worked with config file.

Settings from argument generally take more priority over config file. When it's not given explicitly via argument, the config file takes over.

For boolean argument, provide the argument means switch true/false, but just 1 state. If the argument default is false, and setting in config file is true, Once I want to turn off the switch, I have to change the config file.

For example, a case like this:

If I want to enable the hack, I can pass arg --enable-hack, then the setting in config file will be ignored. But once I want to disable the hack temporary, I have to change the config file as no argument provided means using config file. Or I can add another arg --disable-hack, and then pass the argument to explicitly disable the hack, which does not seem to be good.

It would be better if a boolean argument can also accept the form of --enable-hack=true/false

wanjiadenghuo111 commented 12 months ago

亲,来信已经收到!祝你快乐!

p-ranav commented 12 months ago

In the current library, this can be done by writing a custom action for each type of "true" "false" string that you want handled.

int main(int argc, char *argv[])
{
    argparse::ArgumentParser program("program_name");

    program.set_assign_chars("=:");

    program.add_argument("--enable-hack")
        .default_value(false)
        .action([](const auto& str) {
            return (str == "true");
        });

    try {
        program.parse_args(argc, argv);
    } catch (const std::runtime_error &err) {
        std::cerr << "argparse failed with:" << err.what() << "\n";
        std::cerr << program;
        return 1;
    }

    std::cout << "Hack enabled: " << std::boolalpha << program.get<bool>("--enable-hack") << "\n";

    return 0;
}
foo:bar $ ./main
Hack enabled: false
foo:bar $ ./main --enable-hack=true
Hack enabled: true
rtgiskard commented 12 months ago

Just update to the latest version 3.0, find that this behavior may not be the desired one:

For a piece of code like this:

  program.set_assign_chars("=");
  program.add_argument("--enable-hack")
      .default_value(false)
      .action([](const auto &str) { return (str == "true"); });

  program.add_argument("--enable-a").flag();

--enable-hack true, --enable-hack=true seems to be equivalent, but --enable-hack will apply parser["--enable-hack"]==false, which is not desired. And the help message print as:

Optional arguments:
  -h, --help     shows help message and exits 
  -v, --version  prints version information and exits 
  --enable-hack  [nargs=0..1] [default: false]
  --enable-a

And for general boolean argument like this:

  program.set_assign_chars("=");

  program.add_argument("--enable-hack")
      .default_value(false)
      .implicit_value(true)
      .action([](const auto &str) { return (str == "true"); });

  program.add_argument("--enable-hack").flag()
      .action([](const auto &str) { return (str == "true"); });

--enable-hack=true will be treated as positional arguments, which is not desired either.

It would be better to have a native boolean argument to handle the flexible switch via --boolean-a=true or sth similar

let me see, is it possible to have a boolean argument defined like this:

  program.add_argument("--enable-hack").flag();

and support the following equivalent arguments: