@@ -186,21 +186,13 @@ class parser
186186 char const * const * const argv,
187187 update_notifications version_updates = update_notifications::on,
188188 std::vector<std::string> subcommands = {}) :
189- version_check_dev_decision{version_updates},
190- subcommands{std::move (subcommands)}
189+ argc{argc},
190+ argv{argv},
191+ version_check_dev_decision{version_updates}
191192 {
192- for (auto & sub : this ->subcommands )
193- {
194- if (!std::regex_match (sub, app_name_regex))
195- {
196- throw design_error{" The subcommand name must only contain alpha-numeric characters or '_' and '-' "
197- " (regex: \" ^[a-zA-Z0-9_-]+$\" )." };
198- }
199- }
200-
201193 info.app_name = app_name;
202194
203- init (argc, argv );
195+ add_subcommands ( std::move (subcommands) );
204196 }
205197
206198 // !\brief The destructor.
@@ -666,13 +658,92 @@ class parser
666658 */
667659 parser_meta_data info;
668660
661+ /* !\brief Adds subcommands to the parser.
662+ * \param[in] subcommands A list of subcommands.
663+ * \throws sharg::design_error if the subcommand name contains illegal characters.
664+ */
665+ void add_subcommands (std::vector<std::string> const & subcommands)
666+ {
667+ for (auto const & sub : subcommands)
668+ {
669+ if (!std::regex_match (sub, app_name_regex))
670+ {
671+ std::string const error_message =
672+ detail::to_string (std::quoted (info.app_name ),
673+ " contains an invalid subcommand name: " ,
674+ std::quoted (sub),
675+ " . The subcommand name must only contain alpha-numeric characters " ,
676+ " or '_' and '-' (regex: \" ^[a-zA-Z0-9_-]+$\" )." );
677+ throw design_error{error_message};
678+ };
679+ }
680+
681+ auto & parser_subcommands = this ->subcommands ;
682+
683+ #if 0
684+ auto sorted = subcommands;
685+ std::ranges::sort(sorted);
686+ std::vector<std::string> difference{};
687+ std::ranges::set_intersection(sorted, std::ranges::unique(sorted), std::back_inserter(difference));
688+ if (!difference.empty())
689+ {
690+ auto view = std::views::transform(difference,
691+ [](auto const & val)
692+ {
693+ return std::quoted(val);
694+ });
695+ std::string const error_message =
696+ detail::to_string("add_subcommands()'s arguments list contains duplicate elements for ",
697+ std::quoted(info.app_name),
698+ " : ",
699+ view,
700+ ".");
701+ throw design_error{error_message};
702+ }
703+
704+ auto duplicate_subcommands = std::ranges::search(parser_subcommands, subcommands);
705+ if (duplicate_subcommands)
706+ {
707+ auto view = std::views::transform(duplicate_subcommands,
708+ [](auto const & val)
709+ {
710+ return std::quoted(val);
711+ });
712+ std::string const error_message =
713+ detail::to_string(std::quoted(info.app_name), " already contains subcommands: ", view, ".");
714+ throw design_error{error_message};
715+ }
716+ #endif
717+
718+ #ifdef __cpp_lib_containers_ranges
719+ parser_subcommands.append_range (subcommands);
720+ #else
721+ parser_subcommands.insert (parser_subcommands.end (), subcommands.cbegin (), subcommands.cend ());
722+ #endif
723+
724+ std::ranges::sort (parser_subcommands);
725+ auto const [first, last] = std::ranges::unique (parser_subcommands);
726+ parser_subcommands.erase (first, last);
727+
728+ init ();
729+ }
730+
669731private:
670732 // !\brief Keeps track of whether the parse function has been called already.
671733 bool parse_was_called{false };
672734
735+ // !\brief Keeps track of whether the init function has been called already.
736+ bool init_was_called{false };
737+
673738 // !\brief Keeps track of whether the user has added a positional list option to check if this was the very last.
674739 bool has_positional_list_option{false };
675740
741+ // !\brief The number of command line arguments.
742+ int argc{};
743+
744+ // !\brief The command line arguments.
745+ char const * const * argv{nullptr };
746+
676747 // !\brief Set on construction and indicates whether the developer deactivates the version check calls completely.
677748 update_notifications version_check_dev_decision{};
678749
@@ -724,16 +795,11 @@ class parser
724795 std::vector<std::string> executable_name{};
725796
726797 /* !\brief Initializes the sharg::parser class on construction.
727- *
728- * \param[in] argc The number of command line arguments.
729- * \param[in] argv The command line arguments.
730- *
731798 * \throws sharg::too_few_arguments if option --export-help was specified without a value
732799 * \throws sharg::too_few_arguments if option --version-check was specified without a value
733800 * \throws sharg::validation_error if the value passed to option --export-help was invalid.
734801 * \throws sharg::validation_error if the value passed to option --version-check was invalid.
735802 * \throws sharg::too_few_arguments if a sub parser was configured at construction but a subcommand is missing.
736- *
737803 * \details
738804 *
739805 * This function adds all command line parameters to the cmd_arguments member variable
@@ -755,10 +821,19 @@ class parser
755821 *
756822 * If `--export-help` is specified with a value other than html, man, cwl or ctd, an sharg::parser_error is thrown.
757823 */
758- void init (int argc, char const * const * const argv )
824+ void init ()
759825 {
760826 assert (argc > 0 );
761- executable_name.emplace_back (argv[0 ]);
827+
828+ if (init_was_called)
829+ {
830+ cmd_arguments.clear ();
831+ }
832+ else
833+ {
834+ executable_name.emplace_back (argv[0 ]);
835+ init_was_called = true ;
836+ }
762837
763838 bool special_format_was_set{false };
764839
0 commit comments