From b0f19cba9c955bdd3e97370652abae642075ebbe Mon Sep 17 00:00:00 2001 From: naoto Date: Sat, 3 Jan 2026 20:31:06 +0900 Subject: [PATCH 1/3] add test cases --- test/test_optional_arguments.cpp | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/test_optional_arguments.cpp b/test/test_optional_arguments.cpp index 74a4c25a..6647fc71 100644 --- a/test/test_optional_arguments.cpp +++ b/test/test_optional_arguments.cpp @@ -202,3 +202,50 @@ TEST_CASE("Parse arguments of different types" * REQUIRE(program["-string-view"] == true); REQUIRE(program["-builtin"s] == true); } + + +TEST_CASE("Flag with nargs(0,1) stores implicit when no value"* + test_suite("optional_arguments")){ + argparse::ArgumentParser program("prog"); + bool value = false; + program.add_argument("--foo").store_into(value).nargs(0, 1); + program.parse_args({"prog", "--foo"}); + REQUIRE(value == true); +} + +TEST_CASE("Flag with nargs(0,1) respects explicit value"* + test_suite("optional_arguments")) { + argparse::ArgumentParser program("prog"); + bool value = false; + program.add_argument("--foo").store_into(value).nargs(0, 1); + SUBCASE("test with explicit '0' value") { + program.parse_args({"prog", "--foo", "0"}); + REQUIRE(value == false); + } + SUBCASE("test with explicit '1' value") { + program.parse_args({"prog","--foo","1"}); + REQUIRE(value == true); + } +} + +TEST_CASE("nargs(0,1) default-only without value" + * test_suite("optional_arguments")) { + argparse::ArgumentParser program("prog"); + bool value = false; + program.add_argument("--foo").default_value(true).nargs(0, 1).store_into(value); + REQUIRE_NOTHROW(program.parse_args({"prog", "--foo"})); + REQUIRE(value == true); + REQUIRE(program.get("--foo") == true); +} + +TEST_CASE("nargs(0,1) implicit when followed by another option" + * test_suite("optional_arguments")) { + argparse::ArgumentParser program("prog"); + bool foo = false; + std::string bar; + program.add_argument("--foo").store_into(foo).nargs(0, 1); + program.add_argument("--bar").store_into(bar); + program.parse_args({"prog", "--foo", "--bar", "value"}); + REQUIRE(foo == true); + REQUIRE(bar == std::string("value")); +} From 41b6ab2ef9758854f7883aca35172ab374b436b0 Mon Sep 17 00:00:00 2001 From: naoto Date: Sat, 3 Jan 2026 20:46:09 +0900 Subject: [PATCH 2/3] adapt to nargs(0,1) --- include/argparse/argparse.hpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 06d30fd4..b60ad44d 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -698,8 +698,17 @@ class Argument { if (m_default_value.has_value()) { var = std::any_cast(m_default_value); } - action([&var](const auto & /*unused*/) { - var = true; + action([&var](const std::string &s) { + if (s.empty()) { + var = true; // implicit flag + return var; + } + try { + int v = details::parse_number()(s); + var = (v != 0); + } catch (...) { + var = true; // fallback to true + } return var; }); return *this; @@ -1012,6 +1021,15 @@ class Argument { (m_choices.has_value()) ? passed_options : m_num_args_range.get_max(); const auto num_args_min = m_num_args_range.get_min(); std::size_t dist = 0; + auto run_actions_empty = [&]() { + for (auto &action : m_actions) { + std::visit([&](const auto &f) { f({}); }, action); + } + if (m_actions.empty()) { + std::visit([&](const auto &f) { f({}); }, m_default_action); + } + m_is_used = true; + }; if (num_args_max == 0) { if (!dry_run) { m_values.emplace_back(m_implicit_value); @@ -1041,6 +1059,15 @@ class Argument { std::string(m_used_name) + "'."); } } + if (dist == 0) { + // when nargs(0,1) and no arguments provided + if (!dry_run) { + if (m_implicit_value.has_value()) { + m_values.emplace_back(m_implicit_value); + run_actions_empty(); + } + } + } struct ActionApply { void operator()(valued_action &f) { std::transform(first, last, std::back_inserter(self.m_values), f); From 5fa1c5c0c6c836d5b7867780e7afa2f19d2d8247 Mon Sep 17 00:00:00 2001 From: naoto Date: Sat, 3 Jan 2026 20:47:10 +0900 Subject: [PATCH 3/3] make format --- test/test_optional_arguments.cpp | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test/test_optional_arguments.cpp b/test/test_optional_arguments.cpp index 6647fc71..70ba0b2a 100644 --- a/test/test_optional_arguments.cpp +++ b/test/test_optional_arguments.cpp @@ -203,43 +203,43 @@ TEST_CASE("Parse arguments of different types" * REQUIRE(program["-builtin"s] == true); } - -TEST_CASE("Flag with nargs(0,1) stores implicit when no value"* - test_suite("optional_arguments")){ - argparse::ArgumentParser program("prog"); - bool value = false; - program.add_argument("--foo").store_into(value).nargs(0, 1); - program.parse_args({"prog", "--foo"}); - REQUIRE(value == true); +TEST_CASE("Flag with nargs(0,1) stores implicit when no value" * + test_suite("optional_arguments")) { + argparse::ArgumentParser program("prog"); + bool value = false; + program.add_argument("--foo").store_into(value).nargs(0, 1); + program.parse_args({"prog", "--foo"}); + REQUIRE(value == true); } -TEST_CASE("Flag with nargs(0,1) respects explicit value"* - test_suite("optional_arguments")) { - argparse::ArgumentParser program("prog"); - bool value = false; - program.add_argument("--foo").store_into(value).nargs(0, 1); - SUBCASE("test with explicit '0' value") { - program.parse_args({"prog", "--foo", "0"}); - REQUIRE(value == false); - } - SUBCASE("test with explicit '1' value") { - program.parse_args({"prog","--foo","1"}); - REQUIRE(value == true); - } +TEST_CASE("Flag with nargs(0,1) respects explicit value" * + test_suite("optional_arguments")) { + argparse::ArgumentParser program("prog"); + bool value = false; + program.add_argument("--foo").store_into(value).nargs(0, 1); + SUBCASE("test with explicit '0' value") { + program.parse_args({"prog", "--foo", "0"}); + REQUIRE(value == false); + } + SUBCASE("test with explicit '1' value") { + program.parse_args({"prog", "--foo", "1"}); + REQUIRE(value == true); + } } -TEST_CASE("nargs(0,1) default-only without value" - * test_suite("optional_arguments")) { +TEST_CASE("nargs(0,1) default-only without value" * + test_suite("optional_arguments")) { argparse::ArgumentParser program("prog"); bool value = false; - program.add_argument("--foo").default_value(true).nargs(0, 1).store_into(value); + program.add_argument("--foo").default_value(true).nargs(0, 1).store_into( + value); REQUIRE_NOTHROW(program.parse_args({"prog", "--foo"})); REQUIRE(value == true); REQUIRE(program.get("--foo") == true); } -TEST_CASE("nargs(0,1) implicit when followed by another option" - * test_suite("optional_arguments")) { +TEST_CASE("nargs(0,1) implicit when followed by another option" * + test_suite("optional_arguments")) { argparse::ArgumentParser program("prog"); bool foo = false; std::string bar;