#pragma once #include #include #include #include namespace program { template class Arguments { private: using option_id = std::string; struct Action; struct Argument; struct Flag; struct Option; template struct WithDefault; public: Arguments() = default; Arguments(int argc, char const * const * const argv); std::vector args() const { return {arguments.begin() + argument_names.size(), arguments.end()}; } protected: auto action(std::string const &name, std::string const &description = ""); auto argument(size_t index, std::string const & name, std::string const & description = ""); auto flag(std::string const & name, std::string const & description = ""); auto flag(std::string const & name, char abbrev, std::string const & description = ""); auto option(std::string const & name, std::string const & description = ""); auto option(std::string const & name, char abbrev, std::string const & description = ""); private: void usage() const; void add_options(std::string const & name, char abbrev, std::string const & description, std::vector aliases = {}); option_id id(std::string const & arg) const; option_id id(char arg) const { return id({'-', arg}); } bool is_option(std::string const & arg) const; bool is_option(char arg) const { return is_option({'-', arg}); } bool is_flag(std::string const & arg) const; bool is_flag(char arg) const { return is_flag({'-', arg}); } private: friend struct ArgumentTestHelper; friend int main(int, char const * const *); private: using main_callback_t = std::function; using make_hook_t = std::function; // Metadata variables bool primed_{false}; std::map argument_descriptions; std::map argument_names; std::map option_descriptions; std::map option_names; std::set flag_names; std::map actions; std::map action_descriptions; // Data/Output variables std::string program; main_callback_t main_callback{nullptr}; constexpr static size_t const no_optional_args{~0ul}; size_t optional_from{no_optional_args}; std::vector arguments; std::map> options; std::map flags; }; template struct Arguments::Action { Arguments * self; std::string name; std::string description; template operator T() const; bool primed() const; explicit operator bool() const; }; template struct Arguments::Argument { Arguments * self; size_t index; bool is_optional; std::string name; std::string description; template auto operator=(T && value); template operator T() const; bool primed() const; explicit operator bool() const; }; template struct Arguments::Flag { Arguments * self; std::string name; char abbrev; std::string description; bool default_value; auto operator=(bool && value); operator bool() const; template operator T() const; bool primed(bool inv) const; }; template struct Arguments::Option { Arguments * self; std::string name; char abbrev; std::string description; template auto operator=(T && value); template operator T() const; bool primed() const; explicit operator bool() const; }; template template struct Arguments::WithDefault { B impl; V default_value; template operator T() const { return impl ?: T(default_value); } }; } #include "arguments_impl.hpp" template int typed_main(Args const &, Action const &); #define TYPED_MAIN(tname) \ int typed_main(tname const & args); \ int main(int argc, char const * const * const argv) try { \ tname args(argc, argv); \ return (args.main_callback) ? args.main_callback(args) : typed_main(args); \ } catch (program::ProgramArgumentsError const & pae) { \ std::cerr << "Error in program argument handling: " << pae.what() << "\n"; \ } \ int typed_main(tname const & args)