Skip to content

Implementing the standard variant

The latest proposal for a standard variant is P0088R0, found at http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0088r0.pdf

I have now implemented a superset of the proposal, which can be found at the git repository, https://github.com/jarro2783/thenewcpp/. The two extra features are support for recursive types, and the visitor takes arbitrary extra arguments.

The variant requires C++14, which has made the implementation significantly easier compared to C++11. Return type deduction for functions has meant that I can drop result_type for visitors and I don’t need to rely on complex or redundant uses of decltype.
Read more…

Standards compliant variant

Recently, a proposal was made for a standards compliant variant, which can be found at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4450.pdf. Apparently much has been said about what such a beast would look like, since there are many options for how to handle the edge cases. Nevertheless, a proposal has been made, and here are its key features:

  • It can be empty.
  • No restrictions on the types that can be used with regards to no throw move assignable etc.
  • Provides relational operators which can be used as long as each type T provides T op T, and uses the ordering in the type list if they are not the same type.
  • The return type of visitation can be automatically deduced.
  • All memory is inside the variant object, i.e., it uses no extra heap allocation.

Since my variant is almost there, I have started the work needed to make my variant fit the standard. It will end up being a superset of the standard since I support generic multi-visitation with arbitrary arguments (more on that in another post), and I have a mechanism for recursive variants.

To make my variant not empty there are only a few minor things to do:

  • If the index is -1 on visitation, call the visitor’s operator()()
  • Handle errors so that the index is set to -1 appropriately, and the existing object is destructed.

Otherwise my variant already works.

In starting this, I have noticed that index is a size_t, but that it can also be -1 when empty. I’m not sure if this is an error, or if they intended it to mean the largest number that a size_t can hold.

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.

Follow

Get every new post delivered to your Inbox.

Join 27 other followers