diff --git a/README.md b/README.md index 67061aa..35d4479 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,28 @@ if (auto fn = program.present("-o")) { Similar to `get`, the `present` method also accepts a template argument. But rather than returning `T`, `parser.present(key)` returns `std::optional`, so that when the user does not provide a value to this parameter, the return value compares equal to `std::nullopt`. +#### Deciding if the value was given by the user + +If you want to know whether the user supplied a value for an argument that has a ```.default_value```, check whether the argument ```.is_used()```. + +```cpp +program.add_argument("--color") + .default_value("orange") + .help("specify the cat's fur color"); + +try { + program.parse_args(argc, argv); // Example: ./main --color orange +} +catch (const std::runtime_error& err) { + std::cout << err.what() << std::endl; + std::cout << program; + exit(0); +} + +auto color = program.get("--color"); // "orange" +auto explicit_color = program.is_used("--color"); // true, user provided orange +``` + #### Joining values of repeated optional arguments You may want to allow an optional argument to be repeated and gather all values in one place. diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index ba13792..424731f 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -925,6 +925,13 @@ public: return (*this)[aArgumentName].present(); } + /* Getter that returns true for user-supplied options. Returns false if not + * user-supplied, even with a default value. + */ + auto is_used(std::string_view aArgumentName) const { + return (*this)[aArgumentName].mIsUsed; + } + /* Indexing operator. Return a reference to an Argument object * Used in conjuction with Argument.operator== e.g., parser["foo"] == true * @throws std::logic_error in case of an invalid argument name diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f090973..c981f89 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,6 +30,7 @@ file(GLOB ARGPARSE_TEST_SOURCES test_container_arguments.cpp test_help.cpp test_invalid_arguments.cpp + test_is_used.cpp test_issue_37.cpp test_negative_numbers.cpp test_optional_arguments.cpp diff --git a/test/test_is_used.cpp b/test/test_is_used.cpp new file mode 100644 index 0000000..4d0f7a4 --- /dev/null +++ b/test/test_is_used.cpp @@ -0,0 +1,22 @@ +#include +#include + +using doctest::test_suite; + +TEST_CASE("User-supplied argument" * test_suite("is_used")) { + argparse::ArgumentParser program("test"); + program.add_argument("--dir") + .default_value(std::string("/")); + program.parse_args({ "test", "--dir", "/home/user" }); + REQUIRE(program.get("--dir") == "/home/user"); + REQUIRE(program.is_used("--dir") == true); +} + +TEST_CASE("Not user-supplied argument" * test_suite("is_used")) { + argparse::ArgumentParser program("test"); + program.add_argument("--dir") + .default_value(std::string("/")); + program.parse_args({ "test" }); + REQUIRE(program.get("--dir") == "/"); + REQUIRE(program.is_used("--dir") == false); +}