From 708f63a00d426f3ffef54f663ae31e6ab9803ac4 Mon Sep 17 00:00:00 2001 From: "killua.z" Date: Tue, 5 May 2026 11:20:53 +0400 Subject: [PATCH] feat: implement reference capture mode. --- examples/test/main.cpp | 11 +++++++++++ src/headers/parser/argument_builder.hpp | 17 +++++++++++++---- src/headers/parser/parser_v2.hpp | 22 +++++++++++++++++++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/examples/test/main.cpp b/examples/test/main.cpp index 6492d5e..09561d1 100644 --- a/examples/test/main.cpp +++ b/examples/test/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,8 @@ class parser_trait> { >; }; +using namespace argument_parser::v2::flags; + auto main() -> int { argument_parser::v2::parser parser(false); @@ -63,6 +66,12 @@ auto main() -> int { .reference(captured_value) .build(parser); + // parser.add_argument({ + // {ShortArgument, "c"}, + // {HelpText, "capture count"}, + // {Reference, &captured_value}, + // }); + argument::start() .short_argument("q") .help_text("Store a boolean flag.") @@ -95,5 +104,7 @@ auto main() -> int { &argument_parser::conventions::gnu_argument_convention }); + std::cout << "captured value: " << captured_value << '\n'; + return 0; } diff --git a/src/headers/parser/argument_builder.hpp b/src/headers/parser/argument_builder.hpp index 9cb5b8f..2de870c 100644 --- a/src/headers/parser/argument_builder.hpp +++ b/src/headers/parser/argument_builder.hpp @@ -184,7 +184,7 @@ public: using next_argument = argument; next_argument next{*this}; - next.m_reference = static_cast(std::addressof(value)); + next.m_reference = std::addressof(value); next.m_value_mode = value_mode::reference; return next; } @@ -273,7 +273,7 @@ private: m_help_text(other.m_help_text), m_required(other.m_required), m_action(other.m_action), - m_reference(other.m_reference), + m_reference(copy_reference(other.m_reference)), m_value_mode(other.m_value_mode) {} template @@ -361,7 +361,7 @@ private: auto build_reference(argument_parser::v2::base_parser& parser) const -> void { auto pairs = make_typed_pairs(); - auto* target = static_cast(m_reference); + auto* target = m_reference; auto key = lookup_key(); if (target == nullptr) { @@ -414,9 +414,18 @@ private: std::string m_help_text{}; bool m_required = false; std::shared_ptr m_action{}; - void* m_reference = nullptr; + store_type* m_reference = nullptr; value_mode m_value_mode = value_mode::unresolved; + template + static auto copy_reference(other_store_type* reference) -> store_type* { + if constexpr (std::is_same_v) { + return reference; + } else { + return nullptr; + } + } + template friend class argument; }; diff --git a/src/headers/parser/parser_v2.hpp b/src/headers/parser/parser_v2.hpp index abbe172..bfea633 100644 --- a/src/headers/parser/parser_v2.hpp +++ b/src/headers/parser/parser_v2.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ namespace argument_parser::v2 { class base_parser : private argument_parser::base_parser { public: - template using typed_flag_value = std::variant, bool, int>; + template using typed_flag_value = std::variant, bool, int, T*>; using non_typed_flag_value = std::variant; template using typed_argument_pair = std::pair>; @@ -145,6 +146,22 @@ namespace argument_parser::v2 { required = true; } + if (argument_pairs.find(add_argument_flags::Reference) != argument_pairs.end()) { + if (!IsTyped) { + throw std::logic_error("Reference argument must be typed"); + } + + found_params[extended_add_argument_flags::Action] = true; + if constexpr (!std::is_same_v) { + auto ref = get_or_throw(argument_pairs.at(add_argument_flags::Reference), "reference"); + action = helpers::make_parametered_action([ref](T const& t) { + *ref = t; + }).clone(); + } else { + throw std::logic_error("Reference argument must not be void"); + } + } + auto suggested_add = suggest_candidate(found_params); if (suggested_add == candidate_type::unknown) { throw std::runtime_error("Could not match any add argument overload to given parameters. Are you " @@ -166,8 +183,7 @@ namespace argument_parser::v2 { } } - base::add_argument(short_arg, long_arg, help_text, *static_cast(&(*action)), - required); + base::add_argument(short_arg, long_arg, help_text, *static_cast(&(*action)), required); break; case candidate_type::store_other: if (help_text.empty()) {