Command Line Flags in C++
A Minimalist's Guide
You are programming a tool in C++. Not a huge tool, not a tool where you care
enough about performance to say, use faster data structures than those provided
by the standard library, but one where you feel compelled to add some useful
options. After a brief and uninspiring survery of the field you settle on the
old standard for implementing program settings, you’re going to parse argv
.
Parsing command line options falls into the nightmare zone of complexity. It is not so trivial that there’s a single obvious approach, nor is it difficult enough to be solely the domain of white papers published by subject matter experts. Rather it’s an approachable problem that everyone likes to take a swing at it, and following that swing run to write a blog post about their clever little solution; completely flooding search results with endless mediocre code.
With that in mind, here is my clever little solution.
A Little Cleverness
The requirements for my argv
handler were thus:
- Vaguely declarative
- Produces a POD struct
- No outside dependencies
- Trivial to add and remove settings
Since I want a POD struct at the end of this, that’s as good a place to start as any:
Some interesting notes about Figure 1:
help
andverbose
are bools, to be controlled with simple toggle flagsoutfile
requires a parameter and cannot be handled by a toggle flaginfile
is intended to flagless, set when a parameter is not a recognized flagvalue
is neither string or bool, so some sort of conversion will need to be done
My preferred way to switch on strings is to use a map to std::function
:
In Figure 2 we have an unordered map that when passed a string will
produce a lambda (or other std::function
thingy) which can perform the
applicable modification to MySettings
. If this seems extremely obvious and
simple to you, that’s because it is.
As a point of style, it may be appropriate to use a macro here to minimize repetition and make the code more declarative:
Of course, there are legitimate schools of thought which teach that the C preprocessor is of the devil. My immortal soul is worth little and less to me personally, so I like the macro.
For the single argument parameters we simply iterate on this approach. Our
lambdas will now take two arguments, the first being the MySettings
struct
and the second being the string argument:
It should be clear from this point that this approach can be further iterated
to support flags with arbitrary numbers of arguments and parsing complexity.
All that’s left to do is put the pieces together and actually parse argv
.
Putting the Pieces Together
We’re going to need a function that does four things in the following order:
- Check if a string from
argv
is a NoArg option, and if so invoke the appropriate handler - Check if the string is a OneArg option, and if so collect the string argument (throwing if no such argument exists), then invoke the appropriate handler
- Check if
infile
has been set, and if not set it with the string - Warn if
infile
has already been set and the flag is unrecognized
Let’s do it:
Final Thoughts
Parsing argv
is not a hard problem and I make no pretence that the solution
presented here is innovative or ground breaking. Yet if the internet is to be
believed handling these humble flags requires at least one operating system
specific framework or a single header file copied from Dr. Dobbs circa 2003.
Dependencies are not necessarily bad things, but C++ is not Javascript. There’s no need to pull in outside frameworks to solve a problem we can hack in a few dozens lines of code ourselves.
See also: Addendum: Handling Positional Arguments