Skip to content

Lightweight c++ options parser

Using the new C++11 regular expressions, command line option parsing becomes trivial. I wrote a lightweight command line options parser because I was unsatisfied with all of the other libraries out there. They either do not support the syntax that I like, or they are bloated, trying to do too much.

There are two pieces of syntax that need to be parsed in specifying command line options:

  • the specification of which options to recognise, and
  • the command line options themselves.

To recognise these, we have two regular expressions. For the first, we want to be able to write something like "f,file", to specify a short and long option, where either are optional. For the second, we want to recognise long options, with or without =, and short options that can be grouped together, with the last option being able to take a parameter.

The two regular expressions are:

    std::basic_regex<char> option_matcher
      ("--([[:alpha:]][-_[:alpha:]]+)(=(.*))?|-([[:alpha:]]+)");

    std::basic_regex<char> option_specifier
      ("(([[:alpha:]]),)?([[:alpha:]][-_[:alpha:]]+)");

Then the rest of the code is there to loop through the options, ask the regex to match them, and store them somewhere.

The library can be found at http://github.com/jarro2783/cxxopts.

auto considered awesome

My last post about why you might not want to use auto may have left some people thinking that I think you shouldn’t use it. In fact I think you should almost always use it, as suggested in http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/ However, like everything in C++, you should know what you are doing, because if you don’t, when you shoot yourself in the foot, you will probably blow your whole leg off.

You should read the above article, because it is a comprehensive discussion of why you might or might not want to use auto, and why you should use it all the time. Here I will add some points to the discussion about using it so that you don’t get yourself into trouble.

So now, I will go through every point in my last post, and then some.

Read more…

C++14 is on the way

According to https://isocpp.org/blog/2014/08/we-have-cpp14, the C++14 standard has been approved, and the official document is being finalised.

C++14 has some interesting new features, and relaxes some of the restrictions to the structures introduced by C++11, these include:

  • templated variables
  • auto in lambda functions
  • less restrictions on the use of constexpr
  • binary literals

auto considered harmful

So the auto keyword is wonderful isn’t it? Maybe, maybe not. Whilst it can reduce the clutter when dealing with long type names, especially with templates, it has a few disadvantages.

const iterators

Suppose that you have a non-const reference to a container that you wish to iterate through, and not change. You might do something like:

f(Container& c)
{
  auto iter = c.begin();
  while (iter != c.end())
  {
    //do something here
    ++iter;
  }
}

This would be wrong, because what you want is a constant iterator into the container, since you are not changing it. There are two ways to fix it, by using a for each loop or cbegin and cend. With a for each loop you get a reference to the item.

for (const auto& v : c)
{
  //do something here
}

when you actually want the iterators, you can use auto iter = c.cbegin().

Read more…

Delegating constructors

A feature that I had been waiting a long time for is the ability to delegate constructors. To delegate a constructor means that one constructor can call another to initialise the object. When member object initialisation needed to be shared between constructors, or one constructor was the same as another but with some default arguments, the only way to do this was to either duplicate code or call some common function. Both have their problems, the first being that duplicated code is usually bad, the second being that you throw out any initialisation list advantages that you might get by calling some common function in the body of the constructor. Delegating constructors fixes this.

The syntax is quite simple, you simply call the constructor as the only item in an initialiser list. For example, the default constructor delegates to the integer constructor with the argument 42.

class C
{
  public:

  C(int) { }
  C() : C(42) { }
};

The standard specifies that if a constructor delegates to itself, the program is ill-formed. It also states that in that case no diagnostic is required. Given this example right out of the standard

class C
{
  public:

  C(int) { }
  C() : C(42) { }
  C(char) : C(42.0) { }
  C(double) : C('a') { }
};

int main()
{
  C c('b');
  return 0;
}

Clang complains with the following error

delegate.cpp:8:15: error: constructor for 'C' creates a delegation cycle
      [-Wdelegating-ctor-cycles]
  C(double) : C('a') { }
              ^
delegate.cpp:7:3: note: it delegates to
  C(char) : C(42.0) { }
  ^
delegate.cpp:8:3: note: which delegates to
  C(double) : C('a') { }
  ^
1 error generated.

GCC issues no such error, and compiles. The resulting executable crashes with a stack overflow. So be careful when you delegate constructors that you don’t create an infinite loop, because your compiler might not pick it up.

The tuple

The addition of variadic templates allows an arbitrary-types tuple class to be added to C++. The tuple is essentially an unnamed struct with positional arguments — its elements are accessed through their position rather than by a name. It is a generalised version of the pair class.

Firstly, it is defined in the header <tuple>. To define a tuple, simply use std::tuple with template arguments being the types that you want to be contained in the tuple.

For example, to declare a tuple whose three fields are char, int and string, you would write

typedef std::tuple<char, int, std::string> MyTuple;

Read more…

Code on github

Code that I post here is available on the github repository https://github.com/jarro2783/thenewcpp

You can clone it with

git clone https://github.com/jarro2783/thenewcpp.git

There are standalone examples and actual code like the Variant. Any actual code is in the directory “juice”, and in the namespace Juice. Any new code I make will be added to the namespace Juice to build up the Juice C++11 project. It’s a play on Boost and the Boost Juice brand, and the project’s tagline is Juice up your C++11.

Follow

Get every new post delivered to your Inbox.