p-ranav / argparse

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

`store_into` is incompatible with `required` #385

Open noajshu opened 3 weeks ago

noajshu commented 3 weeks ago

Previously in https://github.com/p-ranav/argparse/pull/33 a helpful feature required() was added with these rules:

But if we use the store_into feature, it is incompatible with required. Namely, it cannot recognize that an argument was passed and stored into the specified variable.

MWE:

#include <argparse/argparse.hpp>
int main(int argc, char* argv[]) {
  argparse::ArgumentParser program("cool binary");
  size_t num_threads;
  program.add_argument("--threads")
      .help("Number of threads to use")
      .metavar("N")
      .required()
      .scan<'u', size_t>()
      .default_value(size_t(1))
      .store_into(num_threads);
  program.add_argument("--boxes")
      .help("Number of boxes to use")
      .metavar("B")
      .required()
      .scan<'u', size_t>()
      .default_value(size_t(1));

  try {
    program.parse_args(argc, argv);
  } catch (const std::exception& err) {
    std::cerr << err.what() << std::endl;
    std::cerr << program;
    return EXIT_FAILURE;
  }

  size_t num_boxes = program.get<size_t>("--boxes");

  std::cout << "got num_threads = " << num_threads
            << " num_boxes = " << num_boxes << std::endl;
}

Test script:

clang++ -I argparse/include/ example.cc -o example
for a1 in " " "--threads " "--threads 2 "; do
  for a2 in " " "--boxes " "--boxes 3 "; do
    echo ./example $a1 $a2
    ./example $a1 $a2
  done
done

Output (edited for clarity):

# This works (falls back to default values):
./example
got num_threads = 1 num_boxes = 1

# This raises an exception, as it should
./example --boxes
--boxes: no value provided.

# This also works:
./example --boxes 3
got num_threads = 1 num_boxes = 3

# This raises an exception, as it should
./example --threads
--threads: no value provided.

# This raises an exception, as it should
./example --threads --boxes
--boxes: no value provided.

# This raises an exception, as it should
./example --threads --boxes 3
--threads: no value provided.

# This fails, raising an exception even though `--threads` has a value.
./example --threads 2
--threads: no value provided.

# This raises an exception, as it should
./example --threads 2 --boxes
--boxes: no value provided.

# This fails, raising an exception even though `--threads` has a value.
./example --threads 2 --boxes 3
--threads: no value provided.
geon6 commented 6 days ago

It may make sense https://geon6.github.io/posts/argparse-issue-385/