58 comments

[ 3.0 ms ] story [ 119 ms ] thread
This looks cool but c++17 is required (as far as I can tell, since it requires std::optional), so it's difficult to use for many things until all my colleagues (and their clusters) upgrade their compilers.
Might be possible to substitute with `absl::optional` for the time being.
It's sort of weird to drag in absl to get a flags library.
I switched from gflags to absl::flags and I like it, though there are recommendations against using them too much - https://abseil.io/tips/45 and https://abseil.io/tips/103 (one of my first surprises starting at google, was that binaries (e.g. "exe's") would have thousands of options, just adding a new library to your binary, and more flags are there). I actually like that one, as rather than configuring top-down everything, one can directly "inject" values - for example if you were told to switch from one library to the other, and change your borg template for launching jobs, that new borg template that you've used would have flags set (by another team). Then that team can take it further and modify them if needed, thus allowing them to control their part of the software in your own deployed binary. (This way experiments can be rolled out too, or who knows what else).
I don't think it's weird to use absl flags, I think it would be weird to import absl to support some other flags library, and not use absl flags.
I get it, I'm using it in one project myself, and happy. I do wish though if namespaces were kept - e.g. if there is ambiguity in the names, one can resolve with full namespace (but maybe that also creates an issue, as previously existing invocations may help, so it's like - you better don't rely on C++ namespaces as you may need to fully qualify a flag later and that could be problematic).. Hmm..
I hope you can sooner than later. It really is a good upgrade and allows for some really nice ways of expressing code.
While I can understand that problem, I think it's a reasonable time to target C++17. In fact I would be somewhat weary of new libraries that use something prior of c++17.
Then upgrade their compilers, it's not as big a jump as c++11 was. It's not bleeding edge.

The only legitimate case I've seen for C++ <17 is if you need to compile on MacOS <= 10.13 for shipping 32 bit binaries on Mac, where C++17 features are experimental in XCode (but I haven't had an issue with compatibility in C++17 supported compilers).

CentOS and Debian shipping ancient GCC versions isn't an excuse, it's trivial to update.

> Then upgrade their compilers

If only life was that simple.

For me, yes (I often compile my own gcc). For $USER on $RANDOM_CLUSTER_AT_OTHER_UNIVERSITY_THAT_I_CANT_LOG_INTO, somewhat less easy :).
For the record, CentOS 7 can have gcc-9 by installing devtoolset-9. To get access, you have to start a shell that can see them with "scl enable devtoolset-9 bash".

But people delivering libraries to customers who have elected not to upgrade to current releases are pretty much stuck. It is extremely common for banks, in particular, to still be running gcc-4, and to have no plans ever to upgrade.

It is common at least in banks to have an unbreakable policy never to upgrade software on a server to a version that was not on it when it was unboxed. They may bend just so far as to install back-patched security fixes from the vendor. But a libstdc++.so compatible with a current language Standard? Haha, they say, you must be joking.

It is not unusual for them to still run RHEL 6, or even 5. Bloomberg infamously still has 32-bit SPARCs in the basement, running code compiled only ever with Sun's old compiler.

I had a celebration the day I could push RHEL5 builds off the compatibility raft. Then I spent a couple weeks learning about "new" C++ features I hadn't been able to use because it was too hard to ship code that a customer could build on RHEL5.
Kinda frustrating that in 2020 people complain about a library targetting a 3 years old standard as being "too recent". I'm sure some guys in your company update their node_modules daily and don't get any flak so why not just do the same and use recent tools ? Recent compilers are available for every platform. If you can compile c++17 for commodore 64 and MS-DOS you can for everything else too.
The problem is that not everyone is in control of their computing environment, especially on university clusters. Yes, it's possible to install your own compiler (and in some cases, this might require recompiling a bunch of things due to C++ ABI issues), but for many users, that's a difficult task!
I will try this one out. Here’s a similar library that I’ve had success with before: https://github.com/mmahnic/argumentum I’ve also recently used https://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineP... from OpenCV. It’s useful when you’re already using OpenCV and don’t want to bring in another dependency.
Does anyone have experience with CLI11 [0]?

It seems to have plenty of features and good documentation, plus it's available as a single header file.

[0] https://github.com/CLIUtils/CLI11

I've used it for a couple of small projects. I like it a lot.
Never used it but I’ll give it a look as well.

Looks like everyone and their grandmum makes a command line parser. I can see the draw. It’s a problem with a small scope that you can make a dent in over a weekend.

Yes, worked great for what I needed it for.
This seems to support git-like subcommands. Very, very nice: something mostly missing from other option parsers.

Now does it generate the synopsis part of a man page automatically?

(comment deleted)
Similar lib I made for Python: https://pypi.org/project/func-argparse/

The nice thing with Python is that I implemented a parser from a function signature, and it also works for NamedTuple.

The advantage wrt to other python parser is that it uses the type annotations, instead of guessing

Pretty cool. I like it. Seems one more step toward simplicity than Click for instance.
Thanks for sharing, didn't knew about this one. It seems quite similar indeed.
I'd say the difference with click is that it exposes a nice Python API which makes it easier to meta program CLIs, nice for lazy people.
> Include <structopt/app.hpp> and you're good to go.

I haven't touched C++ for almost a decade but I assume there's (still?) no obvious way that always works to include a dependency package in your build?

For you C++ devs, does this instruction make it obvious how to install this thing into your project?

The instruction makes me suspect that it is a header only library. In this case I would just drop the library source in a dedicated subfolder and expect it to work.

(While it feels better than fighting the system to get a dependency to link properly I would still rather have a proper package manager...)

It requires some digging into the project, because at first glance it doesn't seem to be a simple header-only library. There's a conanfile.py, and a CMakeLists.txt and all sorts of "junk" in the project directory.

But in the end it all seems to come down to this single header file which only depends on C++ stdlib headers and which can be dropped into your own project (which seems to be generated (aka "amalgamated") from multiple smaller header files):

https://github.com/p-ranav/structopt/tree/master/single_incl...

So for typical C++ libraries, this seems quite straightforward to integrate. Usually when looking at a project directory full of random files like this, it's a lot more complicated.

If your project uses CMake, you could

* add the structopt repository as a git submodule to your project

* add something like `add_subdirectory(structopt)` to your top-level CMake script

* add structopt to your target_link_libraries

and you're good to go.

You could do that if you wanted to use git submodules as a sort of poor man's package manager.

But given that it's a header-only library, you can also just download the files, put them in your repo somewhere, and #include them.

If this is something you do in CMake projects, check out FetchContent_Declare — newer CMake versions have this command which downloads a git repository and caches it.

I much prefer this to manually downloading the files, even for header-only libraries. The command provided a nice declarative way of adding a dependency.

It mostly depends on how tight you want the coupling between your project and the dependency in question. It can vary between just getting the source files and building them yourself, just like you do with your own stuff, to just using the public headers plus the relevant static/shared library.

Most of the time, you'll want the latter. The right thing to do in 2020 in that case is IMHO to integrate with a source-based build system like vcpkg, portage (see the prefix project), conan, macports etc. Once the dev-env setup script boils down to just a list of packages, the question of importing third-party dependencies stops being a pain.

I've used most of these (except conan) and vcpkg seems like it's the most painless one, especially because it's a CMake-based system and FWIW CMake seems to be what the C++ world is converging on these days. From my bubble anyway.

During, I think MS Build, Microsoft said, vcpkg, it's their C++ package manager, will support this this year. I read it on their roadmap file in the repo too. VCPKG seems to be the path of least resistance, works accross platforms too
If you have a single source file with no dependencies you can just include it into whatever compilation units you want. That is very easy and elegant. When there are complex dependencies it becomes more problematic.
My previous employer's binary repository settled on using nuget for everything as it was primarily a .NET shop. For our internal C++ projects I made a 'nuget_package_add' CMake script which allowed us to package a lot of our C++ libraries and use them by adding a single line to our CMake scripts.

The main problem was nuget support for C++ DLLs is pretty horrible. I did not want to resort to parsing the .targets file from CMake script so I ended up making non-standard nuget packages that pretty much only worked with our CMake script.

A nice way to declare command line options and arguments. I expected already templates, but some of the generated code looks strange:

static VISIT_STRUCT_CONSTEXPR const int max_visitable_members = 69; https://github.com/p-ranav/structopt/blob/master/single_incl...

This is a copy/paste from a boost header, with some renaming.
Is 'structopt' a common name for this type of argument parser library? I thought it started with the Rust library of the same name but no one has mentioned it yet...

In my opinion, it is _the_ way to quickly create a quality CLI.

https://github.com/TeXitoi/structopt

Half of the argument-parsing libraries contain either “arg” or “opt” due to the initial widespread of getopt or argp. And since both tools parse the arguments into a struct, the choice isn’t that surprising.
If you look at the repo's tags, they also include `clap`, which is the most popular Rust argument parsing library and the one that the original structopt is built upon.

I don't think this coincidence. This looks like it's directly inspired by the Rust library, even though the README gives no indication of that.

Isn't CLAPs origin C++ ?
At least clap for "command line arg parser" has been used in this C++ library from 2006: http://tclap.sourceforge.net/manual.html

Though I'm not sure if the Rust clap has any origins in any specific library for another language.

By the way, using variadic templates it's not hard to write a strictly-typed command-line parser.
I've used http://docopt.org/ in the past for a toy project.

It's an interesting concept where you define the command line "help" syntax and it generates an arguments structure and an associated parser. I've used the C version, I believe the C++ version is better maintained.

Docopt is great until you start digging in and discover the author doesn't have the first clue about parsing. I don't mean in the sense of "weird opinions about recursive descent", but in the literal sense of "has no idea what parsing is or means". The internal implementation is a gigantic clusterfuck of the worst sort of poorly constructed, unmaintainable code you could imagine.

I maintain two ports of docopt and I'm telling you not to use it.