From dc227448f65d948327f3ccd6dd17cfd7926e6b69 Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Wed, 13 Nov 2019 12:54:07 -0600 Subject: [PATCH] Allow actions that return void closes: p-ranav/argparse#39 --- include/argparse.hpp | 34 +++++++++++++++++++++++++++++----- test/test_actions.hpp | 26 ++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index f3ad25a..c506085 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -41,6 +41,7 @@ SOFTWARE. #include #include #include +#include #include namespace argparse { @@ -114,8 +115,14 @@ public: return *this; } - Argument &action(std::function aAction) { - mAction = std::move(aAction); + template + auto action(F &&aAction) + -> std::enable_if_t, + Argument &> { + if constexpr (std::is_void_v>) + mAction.emplace(std::forward(aAction)); + else + mAction.emplace(std::forward(aAction)); return *this; } @@ -139,7 +146,21 @@ public: if (std::any_of(start, end, Argument::is_optional)) { throw std::runtime_error("optional argument in parameter sequence"); } - std::transform(start, end, std::back_inserter(mValues), mAction); + struct action_apply { + void operator()(valued_action &f) { + std::transform(start, end, std::back_inserter(self.mValues), f); + } + + void operator()(void_action &f) { + std::for_each(start, end, f); + if (!self.mDefaultValue.has_value()) + self.mValues.resize(self.mNumArgs); + } + + Iterator start, end; + Argument &self; + }; + std::visit(action_apply{start, end, *this}, mAction); return end; } else if (mDefaultValue.has_value()) { return start; @@ -306,8 +327,11 @@ private: std::string mHelp; std::any mDefaultValue; std::any mImplicitValue; - std::function mAction = - [](const std::string &aValue) { return aValue; }; + using valued_action = std::function; + using void_action = std::function; + std::variant mAction{ + std::in_place_type, + [](const std::string &aValue) { return aValue; }}; std::vector mValues; std::vector mRawValues; size_t mNumArgs = 1; diff --git a/test/test_actions.hpp b/test/test_actions.hpp index 357ad1c..920a500 100644 --- a/test/test_actions.hpp +++ b/test/test_actions.hpp @@ -2,7 +2,7 @@ #include #include -TEST_CASE("Users can use defaul value inside actions", "[actions]") { +TEST_CASE("Users can use default value inside actions", "[actions]") { argparse::ArgumentParser program("test"); program.add_argument("input") .default_value("bar") @@ -16,4 +16,26 @@ TEST_CASE("Users can use defaul value inside actions", "[actions]") { program.parse_args({ "test", "fez" }); REQUIRE(program.get("input") == "bar"); -} \ No newline at end of file +} + +TEST_CASE("Users can add actions that return nothing", "[actions]") { + argparse::ArgumentParser program("test"); + bool pressed = false; + auto &arg = program.add_argument("button").action( + [&](const std::string &) mutable { pressed = true; }); + + REQUIRE_FALSE(pressed); + + SECTION("action performed") { + program.parse_args({"test", "ignored"}); + REQUIRE(pressed); + } + + SECTION("action performed and nothing overrides the default value") { + arg.default_value(42); + + program.parse_args({"test", "ignored"}); + REQUIRE(pressed); + REQUIRE(program.get("button") == 42); + } +}