Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
kkarbowiak committed Jan 23, 2020
1 parent d27bc78 commit 4621f41
Showing 1 changed file with 112 additions and 4 deletions.
116 changes: 112 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,115 @@
# C++ argparse #
# C++ argparse

The aim of this project is to create a C++ equivalent of Python's `argparse` module. It should be modern, header-only and have no external dependencies. I doubt it will ever be on par regarding features, but it is slowly moving towards getting most often used ones.
## Overview

The current implementation requires C++17.
This is a C++ implementation of Python's `argparse` module. The aim is to cover as much functionality as possible and retain `argparse`'s familiarity and ease of use. Everyone who already used Python should feel at home using this library. At the same time, the library is implemented using modern C++ features.

This is work in progress. Use at your own risk, or do not use yet.
## Dependencies

C++ argparse is a header-only library, so its setup is minimal. It has no external dependencies and only uses STL. Since it uses `std::optional`, `std::any`, and some other features, it requires C++17 compiler and standard library.

C++ argparse uses CMake internally, but you don't have to. Just put the header somewhere and point your build system to it.

Unit tests use [doctest](https://github.com/onqtam/doctest) unit testing framework.

## Design considerations

This library strives to provide Python-like arguments parsing experience for C++ developers. However, where Python and C++ clash, this implementation goes the C++ way using its idioms.

### Named parameters

One obvious example is the lack of C++ support for named function parameters. While in Python you can do

```python
parser = argparse.ArgumentParser(prog='app', usage='%(prog)s', description='Showcase app')
```

in C++ you need something else. C++ argparse uses Named Parameter Idiom to achieve similar functionality:

```c++
auto parser = argparse::ArgumentParser().prog("app").usage("%(prog)s").description("Showcase app");
```

It is a bit more verbose and a bit less convenient, but I believe it is still usable.

### Dynamic attribute creation

The `parse_args()` function adds attributes representing parsed arguments to an instance of a `Namespace` class at runtime. In Python creating custom types at runtime is not a problem. Not so in C++. Instead of returning a bespoke class instance, C++ argparse returns a mapping object that uses argument names as keys. This is not as convenient, but not too bad either.

### Type-safety

Python does not have any static type-safety built in and instead depends on runtime checks. Therefore it is fine to pass some things as strings:

```python
parser.add_argument('--option', action='store_true')
```

In C++ we can ask the compiler to help us detect bugs at compile-time, and this is what C++ argparse does. Instead of passing actions as strings, we use `enum`s here:

```c++
parser.add_argument("--option).action(argparse::store_true);
```
If you make a typo, your compiler will let you know.
### Typing
Python is a dynamically typed language while C++ is statically typed. This means that while in Python a function can return any type
```python
def fun(arg):
if not arg:
return None
elif arg == 10:
return 'ten'
else:
return 42
```
in C++ we need a workaround. The workaroud used here is template-based. To get a parsed value, you need to specify which type you expect:
```c++
auto args = parser.parse_args(argc, argv);
auto force = args.get_value<bool>("force");
```
The only exception is `std::string` which is returned by default by the non-template function overload:
```c++
auto args = parser.parse_args(argc, argv);
auto file_name = args.get_value("filename");
```
## Usage
You can find example applications in the project's `examples` subdirectory. A short example follows below:
```c++
#include "argparse.h"
int move_file(std::string const & src, std::string const & dst, bool force, bool verbose);
int main(int argc, char* argv[])
{
auto parser = argparse::ArgumentParser();
parser.add_argument("source").help("source file path");
parser.add_argument("destination").help("destination file path");
parser.add_argument("-f", "--force").help("force copying").action(argparse::store_true);
parser.add_argument("-v", "--verbose").help("prints additional information").action(argparse::store_true);
auto args = parser.parse_args(argc, argv);
auto result = move_file(args.get_value("source"), args.get_value("destination"), args.get_value<bool>("force"), args.get_value<bool>("verbose"));
return result;
}
```
## Supported features
The below list lists features of the `argparse` module that this implementation supports.
## License
This project is released under **MIT** license, so feel free to do anything you like with it.

0 comments on commit 4621f41

Please sign in to comment.