31 KiB
Argument Parser API Documentation
This document covers the public API exposed by:
src/headers/parser/argument_parser.hpp: the original v1 parser surface.src/headers/parser/parser_v2.hpp: the v2 map/initializer-list facade.src/headers/parser/argument_builder.hpp: the staged fluent builder for v2.
The lower-level v1 API still powers the platform parsers and v2. New code will
usually be clearest with argument_parser::v2 and
argument_parser::builder::new_argument(), but the v1 types remain public and
useful when you need direct control over actions, stored values, or positional
registration.
Common Concepts
Argument names are registered without command-line prefixes. Use "v" and
"verbose", not "-v" or "--verbose". The active convention objects decide
which concrete syntaxes are accepted during parsing and how help text is
rendered.
Typed values are parsed through
argument_parser::parsing_traits::parser_trait<T>::parse(std::string const&).
The built-in traits cover common scalar types such as std::string, bool,
int, float, and double; custom value types need a trait specialization.
Trait format_hint and purpose_hint members are used in help text and parse
error messages when available.
Stored values are type-erased internally. Retrieve them with the same type used when the argument was registered.
v1 API: argument_parser.hpp
The public v1 types live in the argument_parser namespace unless otherwise
noted.
action_base
class action_base {
public:
virtual ~action_base() = default;
[[nodiscard]] virtual bool expects_parameter() const = 0;
virtual void invoke() const = 0;
virtual void invoke_with_parameter(std::string const& param) const = 0;
[[nodiscard]] virtual std::pair<std::string, std::string> get_trait_hints() const = 0;
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
};
action_base is the polymorphic interface stored by registered arguments.
Application code normally uses action_with_param<T>, action_no_param, or
the overloaded helpers::make_action(...) factories instead of implementing
this interface directly.
expects_parameter()reports whether the action consumes a value token.invoke()runs a no-value action. Onaction_with_param<T>, it throwsstd::runtime_error.invoke_with_parameter(param)runs a value action. Onaction_no_param, the parameter is ignored.get_trait_hints()returns{format_hint, purpose_hint}for typed actions when the parser trait exposes those members.clone()returns a heap-allocated copy used byargument.
action_with_param<T>
template <typename T>
class action_with_param : public action_base {
public:
using parameter_type = T;
explicit action_with_param(std::function<void(T const&)> const& handler);
void invoke(T const& arg) const;
[[nodiscard]] bool expects_parameter() const override;
void invoke() const override;
void invoke_with_parameter(std::string const& param) const override;
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override;
[[nodiscard]] std::unique_ptr<action_base> clone() const override;
};
Adapts a std::function<void(T const&)> into a parser action. During
invoke_with_parameter, the raw string is converted with
parser_trait<T>::parse(param) and the parsed value is passed to the handler.
Parse failures are reported as std::runtime_error with trait-derived hints
when available.
action_no_param
class action_no_param : public action_base {
public:
explicit action_no_param(std::function<void()> const& handler);
void invoke() const override;
[[nodiscard]] bool expects_parameter() const override;
void invoke_with_parameter(std::string const& param) const override;
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override;
[[nodiscard]] std::unique_ptr<action_base> clone() const override;
};
Adapts a std::function<void()> into a flag-style action.
expects_parameter() returns false; invoke_with_parameter(...) ignores the
parameter and runs the no-value handler.
argument_parser::helpers
namespace argument_parser::helpers {
template <typename T>
action_with_param<T>
make_action(std::function<void(T const&)> const& function);
action_no_param
make_action(std::function<void()> const& function);
}
Factory helpers for creating action objects used by base_parser and v2.
parser_settings
struct parser_settings {
bool should_exit_on_error = true;
bool should_exit_on_missing_required = true;
bool should_exit_on_unknown_argument = true;
bool should_exit_on_help = true;
bool ignore_unknown_arguments = false;
bool ignore_errors = false;
};
constexpr static inline parser_settings no_exit{
false,
false,
false,
false
};
parser_settings configures how the parser reacts to help, parse errors,
unknown arguments, and missing required arguments. The default settings preserve
CLI-style behavior: help exits after printing, unknown arguments and parse
errors exit with status 1, and missing required arguments print diagnostics
and help before exiting.
Use argument_parser::no_exit when embedding the parser in tests, tools, or
larger applications that should receive exceptions instead of process exits:
argument_parser::v2::parser parser(argument_parser::no_exit);
For targeted behavior, pass an explicit settings object to the v2 platform parser constructor:
argument_parser::parser_settings settings;
settings.should_exit_on_help = false;
settings.should_exit_on_error = false;
settings.should_exit_on_unknown_argument = false;
settings.should_exit_on_missing_required = false;
settings.ignore_unknown_arguments = true;
argument_parser::v2::parser parser(settings);
The fields have these effects:
should_exit_on_help: controls whether the automatically registered v2-h/--helpaction callsstd::exit(0)after printing help.should_exit_on_error: whentrue, non-unknown parse errors caught byhandle_arguments(...)callstd::exit(1); whenfalse, the exception is rethrown.should_exit_on_unknown_argument: whentrue, unknown arguments caught byhandle_arguments(...)callstd::exit(1); whenfalse, the unknown argument exception is rethrown.should_exit_on_missing_required: whentrue, missing required arguments print diagnostics/help and callstd::exit(1); whenfalse, they throwstd::runtime_error.ignore_unknown_arguments: whentrue, tokens that match no convention and cannot be consumed as positionals are skipped.ignore_errors: reserved in the public settings struct in the current worktree; no runtime branch currently reads it.
argument
class argument {
public:
argument();
template <typename ActionType>
argument(int id, std::string name, ActionType const& action);
argument(argument const& other);
argument& operator=(argument const& other);
argument(argument&& other) noexcept = default;
argument& operator=(argument&& other) noexcept = default;
[[nodiscard]] bool is_required() const;
[[nodiscard]] std::string get_name() const;
[[nodiscard]] bool is_invoked() const;
[[nodiscard]] bool expects_parameter() const;
[[nodiscard]] std::string get_help_text() const;
[[nodiscard]] bool is_positional() const;
[[nodiscard]] bool is_positional_accumulator() const;
[[nodiscard]] std::optional<int> get_position_index() const;
};
argument is the public descriptor returned by parser lookup operations. It is
copyable; copies clone their stored action.
is_required()reports whether parsing must see this argument.get_name()returns the registered display name. Named options are stored as"<short>|<long>"; positional arguments use their positional name.is_invoked()reports whether the action ran duringhandle_arguments(...).expects_parameter()mirrors the stored action.get_help_text()returns the registration help text.is_positional()identifies positional arguments.is_positional_accumulator()is true for positional accumulators.get_position_index()returns the explicit requested position, orstd::nullopt.
base_parser
class base_parser {
public:
template <typename T>
void add_argument(
std::string const& short_arg,
std::string const& long_arg,
std::string const& help_text,
action_with_param<T> const& action,
bool required);
template <typename T>
void add_argument(
std::string const& short_arg,
std::string const& long_arg,
std::string const& help_text,
bool required);
void add_argument(
std::string const& short_arg,
std::string const& long_arg,
std::string const& help_text,
action_no_param const& action,
bool required);
void add_argument(
std::string const& short_arg,
std::string const& long_arg,
std::string const& help_text,
bool required);
template <typename T>
void add_positional_argument(
std::string const& name,
std::string const& help_text,
action_with_param<T> const& action,
bool required,
std::optional<int> position = std::nullopt);
template <typename T>
void add_positional_argument(
std::string const& name,
std::string const& help_text,
bool required,
std::optional<int> position = std::nullopt);
template <typename T>
void add_positional_accumulator(
std::string const& name,
std::string const& help_text,
action_with_param<T> const& action,
bool required,
std::optional<int> position = std::nullopt);
void on_complete(std::function<void(base_parser const&)> const& action);
template <typename T>
std::optional<T> get_optional(std::string const& arg) const;
[[nodiscard]] std::string build_help_text(
std::initializer_list<conventions::convention const* const> convention_types) const;
argument& get_argument(conventions::parsed_argument const& arg);
[[nodiscard]] std::optional<int> find_argument_id(std::string const& arg) const;
void handle_arguments(
std::initializer_list<conventions::convention const* const> convention_types);
void display_help(
std::initializer_list<conventions::convention const* const> convention_types) const;
protected:
base_parser() = default;
};
base_parser owns registrations, parsed command-line tokens, stored values,
required-argument checks, and completion hooks. Its constructor is protected;
users normally instantiate a concrete parser from <argparse> or a platform
header. Platform parser constructors populate program_name and
parsed_arguments from the native process arguments.
base_parser is not thread-safe. handle_arguments(...) must be called on the
same thread that created the parser or it throws std::runtime_error.
Named Arguments
Use add_argument(...) for short and/or long options. The v1 API uses "-" as
the sentinel for an omitted short or long name.
argument_parser::parser parser;
parser.add_argument<std::string>(
"o",
"output",
"Output file.",
argument_parser::helpers::make_action<std::string>(
[](std::string const& value) {
// use value
}),
true);
parser.add_argument(
"v",
"verbose",
"Enable verbose output.",
false);
Registration fails with std::runtime_error("The key already exists!") if the
short or long key is already registered. Because duplicate checks also see the
"-" sentinel, avoid registering multiple v1 arguments that pass "-" for the
same side unless you have verified that behavior.
The overloads behave as follows:
add_argument<T>(..., action_with_param<T> const& action, bool required)parses a value and invokes the supplied typed action.add_argument<T>(..., bool required)parses a value and stores it internally forget_optional<T>(...).add_argument(..., action_no_param const& action, bool required)invokes a no-value action.add_argument(..., bool required)storestrueinternally when the option is present.
Positional Arguments
parser.add_positional_argument<std::string>(
"input",
"Input path.",
true,
0);
parser.add_positional_argument<int>(
"count",
"Number of iterations.",
argument_parser::helpers::make_action<int>(
[](int value) {
// use value
}),
false);
Positional arguments are matched against tokens that do not match any supplied
convention. You can provide an explicit zero-based position, or omit it to use
the next available positional slot.
add_positional_argument<T>(..., bool required, ...) stores the parsed value
internally under the positional name. The action overload invokes the supplied
typed action.
add_positional_accumulator<T>(...) registers a typed positional action that can
consume repeated positional tokens at its slot. Only one positional accumulator
is allowed, and it must be the last positional argument. Duplicate names,
negative explicit positions, or invalid accumulator placement throw
std::runtime_error.
Parsing
parser.handle_arguments({
&argument_parser::conventions::gnu_argument_convention,
&argument_parser::conventions::gnu_equal_argument_convention,
&argument_parser::conventions::windows_argument_convention,
&argument_parser::conventions::windows_equal_argument_convention,
});
handle_arguments(...) invokes matching actions, records stored values, checks
required arguments, then runs completion hooks. For each token, conventions are
tried in order. If no convention matches, the token is consumed as the next
positional value when one is available. -- forces all following tokens to be
treated as positional values.
Unknown options, missing values, parse failures, unexpected positional values,
and action errors are reported with std::runtime_error. Missing required
arguments print diagnostics and help text, then call std::exit(1).
If a registered argument named h or help is found, the parser invokes that
help argument and returns from argument invocation early. Required checks and
completion hooks still run after invocation returns.
Lookup And Help
if (auto output = parser.get_optional<std::string>("output")) {
// *output is the stored value
}
auto id = parser.find_argument_id("output");
std::string help = parser.build_help_text({
&argument_parser::conventions::gnu_argument_convention,
});
parser.display_help({
&argument_parser::conventions::gnu_argument_convention,
});
get_optional<T>(arg) returns a stored value for a registered short name, long
name, or positional name. It returns std::nullopt when no argument by that name
exists or when no value was stored. If a value exists but T does not match the
stored type, std::any_cast<T> throws std::bad_any_cast.
find_argument_id(arg) returns the internal integer id for a registered short
name, long name, or positional name. get_argument(parsed_argument) resolves a
parsed convention result to an argument& and throws when no match exists.
build_help_text(...) returns formatted usage text. display_help(...) writes
that text to std::cout.
Completion Hooks
parser.on_complete([](argument_parser::base_parser const& state) {
// inspect state.get_optional<T>(...)
});
on_complete(...) appends a callback that runs after successful argument
invocation and required-argument checks.
v2 API: parser_v2.hpp
The v2 API is declared under argument_parser::v2. It provides a
map/initializer-list facade over the v1 base_parser, while still accepting the
same convention objects and action helpers.
Typical use is through the platform alias from <argparse>:
#include <argparse>
using namespace argument_parser::v2::flags;
int main() {
argument_parser::v2::parser parser(argument_parser::no_exit);
parser.add_argument<int>({
{LongArgument, "count"},
{HelpText, "Number of items to process."},
{Required, true},
});
parser.handle_arguments({
&argument_parser::conventions::gnu_argument_convention,
&argument_parser::conventions::windows_argument_convention,
});
auto count = parser.get_optional<int>("count");
}
enum class add_argument_flags
These keys describe an argument passed to v2::base_parser::add_argument.
| Flag | Value type | Meaning |
|---|---|---|
ShortArgument |
std::string |
Short option name, such as "v". |
LongArgument |
std::string |
Long option name, such as "verbose". |
Positional |
std::string |
Registers a positional argument. When present, the positional registration path is used. |
Position |
int |
Optional zero-based position for a positional argument. |
HelpText |
std::string |
Help text shown in generated help output. |
Action |
action_with_param<T> or action_no_param |
Callback invoked when the argument is found. |
Required |
bool |
Marks the argument required when true. |
Reference |
T* |
Stores a parsed typed value into an external object. Cannot be combined with Action. |
Accumulate |
bool or T* |
Repeated-value mode. For std::vector<U>, each parsed U is appended. For int, each occurrence increments the count. |
The argument_parser::v2::flags namespace exposes inline constants with the
same names for concise initializer-list calls.
using namespace argument_parser::v2::flags;
parser.add_argument({
{ShortArgument, "q"},
{HelpText, "Quiet mode."},
});
argument_parser::v2::deducers
template <typename, typename = void>
struct has_value_type;
template <typename T>
struct is_vector;
template <typename T>
constexpr bool is_vector_v = is_vector<T>::test();
These public type traits are used by v2 accumulator logic. has_value_type
detects T::value_type. is_vector<T>::test() and is_vector_v<T> are true
only when T is exactly a std::vector specialization.
argument_parser::v2::base_parser
v2::base_parser is the v2 facade. Concrete platform parsers such as
argument_parser::v2::linux_parser, macos_parser, windows_parser, and the
portable <argparse> alias argument_parser::v2::parser derive from it. The
v2 platform parser constructors accept parser_settings const& settings = {}.
Use the default constructor for normal command-line tools, or pass
argument_parser::no_exit / a custom parser_settings object when the caller
should handle errors without automatic process exits.
The class privately inherits from the v1 argument_parser::base_parser and
re-exposes selected operations.
template <typename T>
using typed_flag_value =
std::variant<std::string, action_with_param<T>, bool, int, T*>;
using non_typed_flag_value =
std::variant<std::string, action_no_param, bool, int>;
template <typename T>
using typed_argument_pair =
std::pair<add_argument_flags, typed_flag_value<T>>;
using non_typed_argument_pair =
std::pair<add_argument_flags, non_typed_flag_value>;
Use typed aliases for arguments that parse a value of T, run an
action_with_param<T>, store into a T, or accumulate values. Use non-typed
aliases for boolean flags and no-parameter actions.
Typed add_argument
template <typename T>
void add_argument(
std::unordered_map<add_argument_flags, typed_flag_value<T>> const& argument_pairs);
template <typename T>
void add_argument(std::initializer_list<typed_argument_pair<T>> const& pairs);
Registers a typed option or positional argument. For non-positional options,
provide at least one of ShortArgument or LongArgument. If only one name is
supplied, the other is internally set to "-" and not registered.
Without Action, Reference, or Accumulate, the parsed T is stored
internally and can be read with get_optional<T>(). For positional arguments,
include Positional; Position can place the argument at a specific zero-based
slot.
int threshold = 0;
parser.add_argument<int>({
{LongArgument, "threshold"},
{Reference, &threshold},
{HelpText, "Store the parsed threshold."},
});
Non-Typed add_argument
void add_argument(
std::unordered_map<add_argument_flags, non_typed_flag_value> const& argument_pairs);
void add_argument(std::initializer_list<non_typed_argument_pair> const& pairs);
Registers a non-typed option or positional argument. For options, provide at
least one of ShortArgument or LongArgument. Without Action, the argument
behaves as a boolean flag: when present, it stores true for
get_optional<bool>().
With Action, provide an action_no_param. Non-typed arguments cannot use
Reference or Accumulate. A non-typed positional argument is stored as
std::string.
parser.add_argument({
{ShortArgument, "v"},
{LongArgument, "verbose"},
{HelpText, "Enable verbose output."},
});
Other Public Operations
argument_parser::base_parser& to_v1();
void handle_arguments(
std::initializer_list<conventions::convention const* const> convention_types);
template <typename T>
std::optional<T> get_optional(std::string const& arg);
using argument_parser::base_parser::display_help;
using argument_parser::base_parser::on_complete;
to_v1() returns a mutable reference to the underlying v1 parser interface.
handle_arguments(...), get_optional<T>(...), display_help(...), and
on_complete(...) follow the v1 behavior described above.
Accumulation
Accumulate has special typed behavior:
T = std::vector<U>registers an argument that accepts repeatedUvalues.T = intregisters a counter-style option; each occurrence increments the count.Accumulateset totruestores the accumulated result internally and makes it available throughget_optional<T>().Accumulateset toT*, orAccumulatecombined withReference, writes directly to an external object.
For vector accumulators, the public argument type is std::vector<U>, but each
individual command-line occurrence is parsed as U.
parser.add_argument<std::vector<int>>({
{LongArgument, "include-id"},
{Accumulate, true},
{HelpText, "May be repeated."},
});
auto ids = parser.get_optional<std::vector<int>>("include-id");
Builder API: argument_builder.hpp
The public builder API lives under argument_parser::builder. It provides a
staged fluent interface for registering arguments with
argument_parser::v2::base_parser.
#include <argument_builder.hpp>
// or
#include <argparse>
using argument_parser::builder::new_argument;
Public Types
non_type is a marker type used before a value-producing mode has been
selected. Application code normally does not need to name it.
builder_mask is a public namespace containing the compile-time machinery used
by argument<mask, store_type>. It exposes mask_type, value_mode,
extra_capability, capability constants such as short_argument,
long_argument, positional, help_text, required, reference,
accumulate, count, store, and flag, plus constexpr helpers such as
bit, has, remove, replace, is_buildable, and
is_build_and_gettable. These are mainly useful for type-level tests or
advanced wrappers.
container<store_type>
template <typename store_type>
class container;
Returned by build_and_get(parser). It is populated after
parser.handle_arguments(...) completes.
store_type get() constreturns the stored value. Call only after the container is populated.store_type& operator*()dereferences the stored value.store_type* operator->()accesses members of the stored value.operator bool()reports whether a value is available.
For builder-managed storage, build_and_get() registers an on_complete
callback that reads the parsed value by lookup key. For
accumulate(existing_vector), the container references the provided vector
directly.
argument<mask, store_type>
template <
argument_parser::builder::builder_mask::mask_type mask =
argument_parser::builder::builder_mask::initial,
typename store_type = argument_parser::builder::non_type>
class argument;
The staged fluent builder. mask enables only valid next methods at compile
time. store_type is the type produced by the selected value mode. Most users
should create builders with new_argument().
Entry Points
static auto argument<>::start() -> argument<builder_mask::initial>;
static inline auto new_argument();
new_argument() is equivalent to argument<>::start().
new_argument()
.long_argument("output")
.store<std::string>()
.required()
.build(parser);
Identifier Methods
At least one identifier method must be used before build(parser) or
build_and_get(parser).
auto short_argument(std::string short_name) const -> argument<..., store_type>;
auto long_argument(std::string long_name) const -> argument<..., store_type>;
auto positional(std::string positional_name) const -> argument<..., store_type>;
auto position(int index) const -> argument<..., store_type>;
short_argument(...) and long_argument(...) set named option identifiers and
can be combined with each other. positional(...) registers a positional
argument and is mutually exclusive with named identifiers. position(...) is
available only after positional(...) and only once. If no value mode is
selected for a positional argument, build(parser) registers a std::string
positional value.
Metadata Methods
auto help_text(std::string help) const -> argument<..., store_type>;
auto required(bool value = true) const -> argument<..., store_type>;
help_text(...) sets generated help text and is single-use. If omitted, v2
generates default text, often using parser trait hints for typed value modes.
required(...) marks the argument required when value is true. There is no
public setRequired(...) method in argument_builder.hpp; the public fluent API
is required(...).
Terminal Value Modes
Exactly one terminal value mode can be selected. Once selected, the other modes are removed from the builder type.
template <typename T = std::string>
auto store() const -> argument<..., T>;
template <typename T>
auto reference(T& value) const -> argument<..., T>;
auto flag() const -> argument<..., bool>;
template <typename T = std::string>
auto accumulate() const -> argument<..., std::vector<T>>;
template <typename T>
auto accumulate(T& value) const -> argument<..., T>;
auto count() const -> argument<..., int>;
auto count(int& value) const -> argument<..., int>;
template <typename Callable>
auto action(Callable&& handler) const -> argument<..., non_type>;
template <typename T = std::string, typename Callable>
auto action(Callable&& handler) const -> argument<..., T>;
store<T>() parses a value and stores it in the parser for later lookup.
store<void>() is rejected at compile time.
reference(T&) parses a value and assigns it directly to an object that must
outlive parsing.
flag() registers a boolean presence flag. It is not available for positional
arguments. Named arguments also default to flag behavior when no terminal mode
is selected.
accumulate<T>() accepts repeated values and stores them as std::vector<T>.
accumulate(existing) appends repeated values into an existing vector. The
existing object must be a std::vector and must outlive parsing.
count() counts how many times a named argument appears. count(int&) writes
the count into an existing integer. count() is not available for positional
arguments.
action(handler) registers a no-value action when handler is invocable as
void(). For positional arguments, the builder adapts it through a
std::string positional action and ignores the parsed positional text.
action<T>(handler) registers a typed action when handler is invocable as
void(T const&). action<void>(...) is rejected at compile time.
Build Methods
auto build(argument_parser::v2::base_parser& parser) const -> void;
auto build_and_get(argument_parser::v2::base_parser& parser) const
-> container<store_type>;
build(parser) registers the configured argument with the parser. It requires
an identifier, dispatches to the selected terminal mode, and defaults to a named
boolean flag or std::string positional value when no terminal mode was
selected. It may propagate validation errors from v2::base_parser.
build_and_get(parser) registers the argument and returns a
container<store_type> for storable modes such as store<T>(), flag(),
default named flags, accumulate<T>(), accumulate(vector&), count(), and
count(int&). It throws std::logic_error for unsupported terminal modes such
as actions. The returned container is normally empty until
parser.handle_arguments(...) completes.
Compile-Time Builder Rules
Invalid fluent chains fail to compile rather than failing at runtime.
build(...)requiresshort_argument(...),long_argument(...), orpositional(...).short_argument(...)andlong_argument(...)can be combined.positional(...)is mutually exclusive with named identifiers.position(...)is available only afterpositional(...)and only once.help_text(...)andrequired(...)are single-use.- Terminal value modes are mutually exclusive.
flag()andcount()are not available for positional arguments.store<void>()andaction<void>(...)are rejected withstatic_assert.accumulate(existing)requiresexistingto be astd::vector.
The header also exposes argument_parser::builder::assertions, a namespace of
small compile-time detection helpers and static_assert checks used to verify
these staged-builder rules. They are not needed for normal parser
configuration.
Complete Builder Example
#include <argparse>
#include <iostream>
#include <string>
#include <vector>
using argument_parser::builder::new_argument;
int main() {
argument_parser::v2::parser parser(argument_parser::no_exit);
int threshold = 0;
std::vector<int> ids;
new_argument()
.long_argument("file")
.store<std::string>()
.required()
.help_text("Input file.")
.build(parser);
new_argument()
.long_argument("threshold")
.reference(threshold)
.build(parser);
new_argument()
.long_argument("id")
.accumulate(ids)
.help_text("Repeatable numeric id.")
.build(parser);
auto verbose = new_argument()
.short_argument("v")
.count()
.build_and_get(parser);
parser.handle_arguments({
&argument_parser::conventions::gnu_argument_convention,
&argument_parser::conventions::windows_argument_convention,
});
if (auto file = parser.get_optional<std::string>("file")) {
std::cout << "file: " << *file << '\n';
}
if (verbose) {
std::cout << "verbosity: " << *verbose << '\n';
}
std::cout << "threshold: " << threshold << '\n';
std::cout << "ids: " << ids.size() << '\n';
}
Caveats
- The v1 API is retained as public compatibility surface, but the newer v2 and builder APIs are generally more ergonomic.
- Parser registration and parsing are single-threaded;
handle_arguments(...)enforces the parser creation thread. handle_arguments(...)resets the current convention list after it returns or throws.- Namespaces named
argument_parser::internal::*are implementation details despite being present in public headers.