p-ranav / argparse Goto Github PK
View Code? Open in Web Editor NEWArgument Parser for Modern C++
License: MIT License
Argument Parser for Modern C++
License: MIT License
Unit tests compile too slow. We should compile different test translation units in parallel. Including and compile catch2 header 20 times is still, but to doctest it isn't an issue. By doing so, when changing a test file, you don't have to recompile all the tests.
action
currently accept only a callable, but since pending member function call obj.fn
isn't a callable object in C++, user can't even use a member function as action
.
Note that mem_fn
doesn't solve the problem. mem_fn
is to wrap a callable object into a function object, but std::function
ctor already does that. So user ends up with three choices:
std::bind
bind_front
in C++20std::thread
ctor like thisthread(&Class::fn, obj) // running obj.fn()
This is done as if forming a bind_front(&Class::fn, obj)
function object and call it with empty argument list. We can do similar thing for action
:
.action(&Class::mem, obj) // calling obj.mem(arg_str)
by implicitly using bind_front
for multi-argument calls to action
.
Note: to get this working for C++17, we can include a homegrown version. Take a look at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0356r5.html#implementability and https://reviews.llvm.org/D60368 . It doesn't have to be perfect.
If an option wants to parse a list of values --foo 1,4,2,6
, then it cannot return std::vector<int>
because this type is considered a container. We probably will never want to parse a list like that (because there are so many good parsing libraries for structural data), so we cannot return the existing containers functionality to "make get<std::vector<T>>()
work" for this demand.
We should consider changing the multivalue argument support. Some observations:
std::vector<std::string>
is verbose to spellstd::array
is not supported (and is tricky to support, because it's not a container that can grow)std::list
is probably never used for lots of reasonsInventing a new set of API is an option, but the present
API (#66) will double the number of names. I think the situation can be improved by blessing a type that is both impossible to be stored in std::any
, and is terse to write -- array type.
Here is how the new get
may look like:
get<T[]>
: returns std::vector<T>
get<T[N]>
: returns std::array<T, N>
if N
== nargs, throws otherwiseget<T>
: returns T
The old spelling get<std::vector<std::string>>
becomes get<std::string[]>
after the change. To not to break everything immediately, we can make the old spelling [[deprecated]]
.
T[]
and T[N]
return entirely different types? I hope users can interpret []
as "returning a type with operator[]
."std::span
(of static extent or dynamic extent)? Technical issue, we only have storage for std::vector<std::any>
rather than std::vector<T>
.It's common to print e.what()
when an exception is thrown. However, some exceptions take strings with a new line while others don't, which is quite annoying.
For example, when some arguments are not provided, the string has a new line. But when the argument is not recognized, the string doesn't have a new line.
Argument with .required()
flag and with default value is not so required (can be omitted in command-line).
I think that [Required]
is not necessary in this case.
A propose skip this text if argument has default value
if (argument.mIsRequired && !argument.mDefaultValue.has_value())
stream << "[Required]";
No macros please.
It's so hard to contribute without automatic code formatting.
I have encountered a linker error that I do not fully understand, and a workaround which I do not fully understand either.
I am using a pattern where I parse a global ArgumentParser
in main() (ish) and then pass around my options (by non-const reference) to multiple translation units where the different parts of the program know what their option keys are and can retrieve their specialized values. This pattern requires including argparse.hpp
in multiple source files so the definition of ArgumentParser
is available in each place it is used. I am compiling with clang 9.0.1.
Everything compiles great this way, but fails to link. The problem is that all the template specializations, such as
template <> constexpr bool standard_signed_integer<signed char> = true;
are multiply defined. Clang only tells me where they are initially defined (exactly one time) but also errors out because they are multiply defined. OK, then:
/usr/bin/ld: src/tickertape/CMakeFiles/tickertape.dir/timescaledb.cpp.o:(.rodata+0x8): multiple definition of `argparse::details::standard_unsigned_integer<unsigned long>'; src/tickertape/CMakeFiles/tickertape.dir/tickertape.cpp.o:(.rodata+0x8): first defined here
I find this confusing because I would have thought that constexpr
would be, well, const, and perhaps not instantiated multiple times in a way that could not be resolved at link. I am no constexpr
expert though, and clearly something else is happening.
I tried using inline:
inline template <> constexpr bool standard_signed_integer<signed char> = true;
which, to my constexpr-standard-naive mind looks silly, and indeed this had no effect.
I also tried reducing this to a declaration and defining the specialization exactly once (in a '.cpp' file):
template <> constexpr bool standard_signed_integer<signed char>;
which did not compile. Finally, I found that this guy is onto something: https://stackoverflow.com/a/47982008
who suggested to put these template specializations in an "unnamed namespace", which I think means that each object file gets their own copy and these have distinct names at link (avoiding the duplicate symbols). This worked.
So this is what I think:
constexpr
.argparse
would ideally support being used in multiple object files linked together without too much hassle. I would actually prefer have to link argparse
and lose the header-only benefits than hack around this linkage problem, but I suspect that we can have both features if we just get this constexpr thing right.So thanks for the great software, but where am I messing this up?
As much as we love it, it's not as well supported.
5/10 would open issue again.
Hello, compiler returns an error when trying to build the code. The problem seems related to the inclusion of the header in the cpp file.
#include <argparse.hpp>
.../argparse/include/argparse.hpp:845:19: error:
no viable overloaded operator[] for type
'const argparse::ArgumentParser'
return (*this)[aArgumentName].get();
~~~~~~~^~~~~~~~~~~~~~
I tested this example with the command line:
$ ./main 1 -abc 3.14 2.718 2 --files a.txt b.txt c.txt 3
and it fails to parse the options.
Keeping the positional arguments together as in:
$ ./main 1 2 3 -abc 3.14 2.71 --files a.txt b.txt c.txt
works.
This is where I noticed that negative numbers fail to parse. See: Issue 24
I am currently running into some issues with implicit values (both happening and not happening). Here is my code:
m_bfm.add_argument("-l", "--load")
.help("load a VMM into the kernel");
m_bfm.add_argument("-u", "--unload")
.default_value(false)
.implicit_value(true)
.help("unload a previously loaded VMM");
m_bfm.add_argument("-x", "--start")
.default_value(false)
.implicit_value(true)
.help("start a previously loaded VMM");
m_bfm.add_argument("-s", "--stop")
.default_value(false)
.implicit_value(true)
.help("stop a previously started VMM");
m_bfm.add_argument("-d", "--dump")
.default_value(false)
.implicit_value(true)
.help("output the contents of the VMM's debug buffer");
m_bfm.add_argument("-m", "--mem")
.default_value(default_heap_size)
.action([](const std::string &val) { return std::stoull(val); })
.help("memory in MB to give the VMM when loading");
m_bfm.parse_args(argc, argv);
I am currently seeing two different issues:
First we need to define what are short options and long options.
Long options: options with names longer than a single character
Short options: options only one character long
Option name is anything after -
or --
(or /
for Windows style as a future extension).
-g3
, -lzlib
(if in the future we allow unified option prefix like a single /
or -
, we may want to disable this parsing mode)=
(or :
for Windows style as a future extension): --foo=a.txt
. This does not work for nargs>1.See also https://docs.python.org/3/library/argparse.html#option-value-syntax
e.g. get<>("--option") should be also avaiable as get<>("option")
.contains() to make it more like STL std::map
I am wondering whether we could add alias for arguments. For example, having --verbose
as an argument, we can also allow -v
as an alias.
So in the code, maybe we can do:
program.add_argument("--verbose")
.default_value(false)
.implicit_value(true)
.alias("-v");
Any advice?
Separately, I've noted about exceptions lightly [...] What is unacceptable is using exceptions for control flow. [...]
On a custom compiler, they may have a way to change all exception handling to calls to
abort()
. Even then, they ask for help, the program just ends. Nothing printed, even if the developer correctly handled it.
I'm trying to use this library through hunter package management system. Would you mind creating some releases once in a while to make it easier to track?
thanks!
Marco
A boss
https://docs.microsoft.com/en-us/cpp/c-language/using-wmain?view=vs-2019
That all C++ cmdline parsing libraries face.
A strong demand is to construct std::path
from command-line arguments, where std::wstring
is native string type for std::path
on Windows.
In past experience, Boost.Program_options (Sphinx docs) is the only library that allowed me to program wmain in real code. But Boost's choice is to template everything on character type while still supporting some codecvt
conversions internally. Using only wvalue
may work for some applications, but in general wcommand_line_parser
is needed.
Given argparse' type erasure design, we have an opportunity to look at the problem differently.
Code:
#include <iostream>
#include <argparse.hpp>
static bool load_xss_libs = true;
int main(int argc, char** argv) {
argparse::ArgumentParser parser("awcsclient");
parser.add_argument("--bootstrap")
.help("Do not autoload XS# libraries")
.default_value(false)
.implicit_value(true);
parser.parse_args(argc, argv);
if (parser["--bootstrap"] == true) {
load_xss_libs = false;
}
std::cout << load_xss_libs << std::endl;
}
A piece of stack trace from GDB:
#2963 0x000055555555a653 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, argc=2, argv=0x5555559640d0) at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:575
#2964 0x0000555555559c10 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, aArguments=std::vector of length 2, capacity 2 = {...})
at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:507
#2965 0x000055555555a653 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, argc=2, argv=0x555555964050) at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:575
#2966 0x0000555555559c10 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, aArguments=std::vector of length 2, capacity 2 = {...})
at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:507
#2967 0x000055555555a653 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, argc=2, argv=0x555555963fd0) at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:575
#2968 0x0000555555559c10 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, aArguments=std::vector of length 2, capacity 2 = {...})
at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:507
#2969 0x000055555555a653 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, argc=2, argv=0x555555963f50) at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:575
#2970 0x0000555555559c10 in argparse::ArgumentParser::parse_args_internal (this=0x7fffffffdb80, aArguments=std::vector of length 2, capacity 2 = {...})
at /home/handicraftsman/Projects/AirWheel/vendor/argparse/include/argparse.hpp:507
Python's argparse has a special action that prints the program version and exits.
Currently printing the program version with this library can be done, but the presence of required arguments will also cause an error.
Support for printing the program version would be nice to have as it's an expected part of any CLI, akin to the --help
option.
Hello,
Running this with clang on Mac OS, when trying to use the library as such:
argparse::ArgumentParser parser{"program"};
parser.add_argument("-t", "--test")
.help("Blah")
.default_value("test");
parser.parse_args(arc, argv);
. . .
parser.get<std::string>("-t"); // Bad any_cast
It seems that the compiler thinks that "test"
is of type const char[5]
.
I tried parser.get<char*>("-t")
with no luck as well.
My only workaround was to statically cast within the default value .default_value(static_cast<std::string>("test"))
.
I realize that this default value arg is getting any casted, but maybe the default value should be templated instead?
Semantically, an optional argument is "optional" to present. But currently, if default_value
isn't set, an optional argument's "not presented" state is not representable. Attempting to access the state (value) will get a logic_error
. Representing the "not presented" state is often necessary because the option's type may leave no value for a good default_value
. For example, an empty string may be an valid argument to an option.
Python argparse has no such problem because any option may be None
. Universally Nullable is a problem, but allowing None
for specific types is adopted by many languages. In C++ it's std::optional<T>
.
I suggest to add a program.present<T>("--option")
API in addition to the existing program.get<T>("--option")
API. The new API returns std::optional<T>
by reifying T
's possible values and the "not presented" state. Its usage looks like the following:
if (auto v = program.present<int>("-n")) {
do_something_with(*v);
}
The name "present" is taken from Java's Optional.ifPresent
. Bike-shedding is mildly welcome.
It would be nice to be able to have a feature whereby you could gather many positional arguments at the end of a command for something like a compiler.
For example, imagine a use case like this:
compiler file1 file2 file3
Currently I don't believe it is possible to do this.
I imagine using it would look something like:
std::vector<std::string> = program.get_trailing();
which would just return all positional arguments at the end regardless of how many.
Is it possible to input negative integers or floats? From what I can see -1
or -1.2e3
are being treated as optional arguments. Maybe std::is_integral
and std::is_floating_point
could be used to first test for integrals or floating points before testing for an optional argument.
These tests fail:
#include <test_parse_args.hpp>
#include <test_positional_arguments.hpp>
#include <test_compound_arguments.hpp>
#include <test_container_arguments.hpp>
Here are the errors and warnings. I'm using Visual Studio 2019 and I get similar errors in Ubuntu 19.04, GCC 8.3
argparse.hpp(444,1): warning C4456: declaration of 'tCurrentArgument' hides previous local declaration
argparse.hpp(423,21): message : see declaration of 'tCurrentArgument'
argparse.hpp(445,1): warning C4456: declaration of 'tIterator' hides previous local declaration
argparse.hpp(434,23): message : see declaration of 'tIterator'
argparse.hpp(132,23): warning C4018: '<=': signed/unsigned mismatch
argparse.hpp(432): message : see reference to function template instantiation 'Iterator argparse::Argument::consume<_InIt>(Iterator,Iterator,std::string)' being compiled
argparse.hpp(432): message : with
argparse.hpp(432): message : [
argparse.hpp(432): message : Iterator=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::string>>>,
argparse.hpp(432): message : _InIt=std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::string>>>
argparse.hpp(432): message : ]
argparse.hpp(255,14): error C2672: 'std::transform': no matching overloaded function found
argparse.hpp(361): message : see reference to function template instantiation 'std::vector<int,std::allocator<int>> argparse::Argument::get<T>(void) const' being compiled
argparse.hpp(361): message : with
argparse.hpp(361): message : [
argparse.hpp(361): message : T=std::vector<int,std::allocator<int>>
argparse.hpp(361): message : ]
argparse\test\test_parse_args.hpp(77): message : see reference to function template instantiation 'T argparse::ArgumentParser::get<std::vector<int,std::allocator<int>>>(const std::string &)' being compiled
argparse\test\test_parse_args.hpp(77): message : with
argparse\test\test_parse_args.hpp(77): message : [
argparse\test\test_parse_args.hpp(77): message : T=std::vector<int,std::allocator<int>>
argparse\test\test_parse_args.hpp(77): message : ]
argparse.hpp(256,1): error C2783: '_OutIt std::transform(const _InIt,const _InIt,_OutIt,_Fn)': could not deduce template argument for '_Fn'
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\algorithm(1314): message : see declaration of 'std::transform'
argparse.hpp(261,14): error C2672: 'std::transform': no matching overloaded function found
argparse.hpp(262,1): error C2783: '_OutIt std::transform(const _InIt,const _InIt,_OutIt,_Fn)': could not deduce template argument for '_Fn'
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\algorithm(1314): message : see declaration of 'std::transform'
The fact that add_argument takes two arguments so that you can state both a "-v" and a "--verbose" doesn't seem to be documented anywhere.
Consider a common pattern: use a dash -
to represent stdin
or stdout
, however, argparse simply considers all arguments which start with a dash as optional arguments. For more information, see this line.
Therefore, I think we can restrict optional arguments to those which
For instance, -
is a positional argument while -m
is an optional argument.
void run_app(const argparse::ArgumentParser &program)
{
// it's not possible to use get() or present() from here because of const
}
It was not clear from the documentation, so I'd like to know if -- is supported as an argument delimiter?
--
is a convention for separating the list of arguments to the program from the list of arguments to be forwarded, an example:./invoke sed --trace X=1 Y=2 Z=3 -- 's/foo/bar/g' fiddling.txt
Where invoke would:
- Recognize
sed
as an optional argument.- Recognize
--trace
as an optional argument.- Recognize
X=1
,Y=2
, andZ=3
as remaining arguments.- Recognize
s/foo/bar/g
andfiddling.txt
as argument to pass tosed
.
Hi,
Could you please be more consistent in tag naming?
Either vMajor.Minor or vMajor.Minor.Patch always?
All tags were v2.0 and now we have v2.0.1.
This brokes some scripts and other automation.
Hey there,
I just tried to print help if no parameter is given but finding the answer was a bit confusing. I would prefer to find a function call in Quick Start that automatically sets this up for me. Shouldn't be a big deal I think :)
Currently it's very inconvenient to make an option in the form of -o output
required. It is not checked if it does not present, if you get("-o")
you get a logic error, which requires lots of post processing. There should be a way to declare that this argument must present. If not presents, exception; if only -o
presents, status quo (a different exception).
Also, the current situation makes -o
equivalent to not presenting if there is a default_value
. I think it's not a very good interface. I tried to simulate a "all or nothing" default value with .implicit_value(x).nargs(1)
, but no luck.
But not both.
We may consider enabling
std::cerr << program;
So that user can use stringstream
if they want to. To make it easier, we can even add a function help
that returns a stringstream
, so that cout << program
is calling cout << program.help().rdbuf()
and program.help().str()
is the previous print_help()
's return value.
Consider deprecating print_help
.
clang generates the following diagnostic fault when compiling using this library:
C:\Src\NetworkedGraphics\out\packages\argparse-src\package\include\argparse\argparse.hpp(196,28): error G3F63BFAE: constexpr variable 'generic_strtod' must be initialized by a constant expression [clang-diagnostic-error]
template <> constexpr auto generic_strtod = strtof;
^
C:\Src\NetworkedGraphics\out\packages\argparse-src\package\include\argparse\argparse.hpp(197,28): error G3F63BFAE: constexpr variable 'generic_strtod' must be initialized by a constant expression [clang-diagnostic-error]
template <> constexpr auto generic_strtod = strtod;
^
C:\Src\NetworkedGraphics\out\packages\argparse-src\package\include\argparse\argparse.hpp(198,28): error G3F63BFAE: constexpr variable 'generic_strtod' must be initialized by a constant expression [clang-diagnostic-error]
template <> constexpr auto generic_strtod = strtold;
^
The quick fix appears to be to remove the indicated constexpr qualifier.
This was picked up running an msvc compile (vs 16.6.0) followed by a clang-tidy run (llvm 9.0). The diagnostic is produced by clang within clang-tidy. clang-tidy is being run with msvc build commands from the configured cmake build database (standard usage).
I created an example by copy & pasting things from the README:
#include "include/argparse.hpp"
int main(int argc, char *argv[]) {
argparse::ArgumentParser program("test");
program.add_argument("square")
.help("display the square of a given number")
.action([](const std::string& value) { return std::stoi(value); });
program.add_argument("--verbose")
.default_value(false)
.implicit_value(true);
program.parse_args(argc, argv);
int input = program.get<int>("square");
if (program["--verbose"] == true) {
std::cout << "The square of " << input << " is " << (input * input) << std::endl;
}
else {
std::cout << (input * input) << std::endl;
}
return 0;
}
And it seems to fail:
$ ./a.out 4
16
$ ./a.out --help
terminate called after throwing an instance of 'std::runtime_error'
what(): help called
Aborted (core dumped)
I think Git-like subcommand can be done by inserting a positional argument and dispatch on subparsers. But this is something argparse should provide directly, with add_subparsers
, for example.
The readme states that you just have to #include <argparse.hpp>
to use the library. However, CMake installs the header into /usr/include/argparse and the target include directory list only specifies /usr/include, so you actually need to use #include <argparse/argparse.hpp>
.
Is this a documentation problem in the readme, or should the CMakeLists.txt be changed from
target_include_directories(argparse INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
to
target_include_directories(argparse INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/argparse>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
?
Hi @p-ranav,
I think it would be nice, if you could print default values specified by "default_value" method when outputting the help text:
program
.add_argument("n")
.help("Number of iterations to be performed")
.default_value("10");
->
...
Positional arguments:
n Number of messages to be sent (default: 10)
this would be really useful
Best regards
Philipp
I made a mistake.
Should be CMAKE_CURRENT_LIST_DIR not SOURCE_DIR. Literally just fixed it as you merged lol.
Hi,
As of Python 3.8.2 argparse can have a custom action class defined and called to execute the default call method where we customize the type of actions that need to be done. Can we also include custom methods in the class ? so that I can call my add_argument as
parser.add_argument('-r', action=Action1.mymethod)
Regards
Ranga
Currently this code isn't allowed in argparse:
program.add_argument(...)
.action([](std::string const& filename)
{
load_cfg(filename);
});
Because argparse internal expects action to return some value, but this one returns void
.
My workaround for that is to define using unit = std::tuple<>;
and returns unit()
, but this isn't nice to C++'s taste.
But it's possible to bake this workaround into argparse (even though there is no any<void>
). Let's say we define a type similar to the unit
above, call is none_internal
. In action
, detects the the input's return type:
template<class F>
Argument &action(F&& f) {
if constexpr (std::is_void_v<std::invoke_result_t<F, std::string>>)
mAction = [f](std::string const& arg) { f(arg); return none_internal(); };
else
mAction = std::move(aAction);
return *this;
}
Currently, we have no predefined actions at all (other than identity), and this is an obvious use case to improve. Asking users to write lambdas to parse raises the bar for use, and difficult to upgrade to a <charconv>
future. For the most common inputs, users should be able to express what do they expect rather than how do they handle.
Python's argparse provides type=int
and type=float
, which do not take hexadecimal inputs and are lack of support for types of different ranges (int
, long
, etc.) We need to able to express both for C++ applications.
I propose to add a .scan
method to the fluent interface, inspired by scanf
. I took the name from scnlib. Usage looks like the following:
program.add_argument("-x")
.scan<'d', int>();
program.add_argument("scale")
.scan<'g', double>();
The non-type template argument specifies how the input "looks like" (where I call it shape), and the type template argument specifies what the return value of the predefined action is. The acceptable types are:
float
, double
, long double
make_unsigned
): signed char
, short
, int
, long
, long long
and the acceptable shapes are:
'a'
: hexadecimal floating-point'f'
: fixed form only'e'
: scientific form only'g'
: general form (either fixed or scientific)'d'
: decimal'u'
: decimal, requires an unsigned type'o'
: octal, requires an unsigned type'x'
: hexadecimal, requires an unsigned type'i'
: anything that from_chars
's grammar accepts in base == 0
The exact grammar should follow from_chars
's requirement. But our first implementation may still use strtol
and strtod
. When encounters errors, throw exceptions similar to what stoi
and stod
do.
from_chars
and strto?
default to parse anything, but Python's type=int
and type=float
only parse decimal. I'm not sure whether we can agree on a default. But when extending this for other types in the future, we may.mAction
in each call to scan
.auto
non-type template parameter help? Sadly no. .scan<int('d')>()
is okay but .scan<(unsigned long)'x'>
is terrible.'X'
? What do you expect them to do? I guess letting them behave as same as the lowercase counterparts is the only reasonable answer. If we agree on that, I'm okay with it.Really neat library. Will you add tags for releases in the future?
The GNU ls
utility allows its flags to be provided anywhere in the commandline, e.g.:
ls -l file1 file2 file3
ls file1 file2 file3 -l
If I understand correctly, .remaining();
does not allow that. Is there a workaround for this or another way to do it?
Currently, specification-wise, the rule isn't clear. Implementation-wise, there is no need to actually interpret the values. I assume that you only want to parse (possibility negative) decimal numbers, without considering locale and thousand separators. In that case, see if the following rule works:
Let x
be a variable of type T
where std::is_arithmetic_v<T>
is true. A pattern S is positional if std::from_chars(&*begin(S), &*end(S), x)
points the ptr
member of the result to &*end(S)
.
Note that this rule deems -inf
, -infinity
, and any form of -nan
to be positional. I think it's desired and it's the status quo in code.
If we are agreed on a rule, we can derive a syntax and only parse that syntax.
See also https://en.cppreference.com/w/cpp/utility/from_chars the syntax is not fully documented here, you will have to lookup strtol
and strtod
as well.
The mParentParsers
member is currently unused. add_parents
's semantics is only merging options. But consider the following: if there is only one parent parser, copy construct from an existing parser has the same effect. We only need a way to change the new instance's mProgramName
.
Does ArgumentParser
has value semantics? ArgumentParser
is copy cunstructible, but a copy of ArgumentParser
is not a distinct copy because shared_ptr
are used without special handling. Parsing in the new parser will affect the old parser. But parent parser also has the "problem," unless this is by design.
If this is not by design, then we'd better to support value semantics in full in both copy-constructor and add_parents
.
Hello.
At first thank you for the library - it's really easy-to-use and feature-enough complete library.
But I have a suggestion - can you create Conan package for the library? Even if library is single header-only using system-independent package manager has a lof of advantages.
One note - wiil be fine if you create release of the library. With it will be easier to create a package.
If you have any questions - just ask here.
if I add an optional arg with a single "-" something like "-o" but don't define how to handle it, I get a seg fault. If I handle it, it's fine. The issue is if the user ads a single - argument that is not supported it will cause a seg fault and there is nothing I can do on my end
should this:
"error: -l: expected 1argument. 0 provided"
be:
"error: -l: expected 1 argument. 0 provided"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.