Sunday, April 24, 2005

ACCU - C++0x

At certain points in my career I've ended up doing alot of C++. Often I wrote a template code, many times in the generative style. I learnt a few lessons from doing this. Firstly, the error messages are terrible. The key reason for this is that the compiler needs all the code present to ensure that the parameter types passed in to the template support the operations that the template code relies on. Hence, the compiler (effectively) expands the code, and only when deep in the bowels of the template code does it report back 'hey, type T doesn't support T::value_type'. When it does that the error trace is enormous, and without a good understanding of the templated code it can be hard to make sense of the error. The second reason was the hoops you had to jump through to ensure that it was clear what type of T you wanted passed in to a template. This is where traits came in, verbose and clunky, but they did the trick, kind of.

All that is going to change - I'd say 'about to change' but the C++0x standard is now scheduled for 2009. C++0x is introducing some features to address the issues raised above, and others. Stroustrup spoke of these at ACCU 2005. Broadly speaking he targetted two areas. Firstly, auto and declspec relate to querying the type information.

e.g.
int doSomething () { };
auto value = doSomething (); // value is an int.

decltype returns a type, e.g. decltype(doSomething) is an int. Syntatically decltype is considered as a typedef name. This allows easy implementation of generic forwarding:

template <class T> auto forwader (T &t) -> decltype (doSomething(t)) {
return doSomething (t);
}

Secondly there is a lot of work being done on improving the checking when using templates, specifically around traits and a desire to seperate the template code from its definition. The traits idiom has been used in the past to:

  • Provide specialisations based on the characteristics of a type (i.e. it is a forward iterator).
  • Explicitly say 'this implementation only works with types with this characteristic'.

C++0x is introducing concepts. The form is yet to be agreed in detail, though there are a number of design ideas on the table. The general idea is that a concept is a set of predicates that assert facts about the sort of type that would work with a specific template. This means that a developer can say 'this template requires type T support ++, assignment, random access' etc. However, it goes further than this and allows new concept to be introduced to represent abstract notions that are specific to a domain, e.g. 'works for small types' or 'works for large types', where the definition of small and large is in the developers mind.

The code may look like this:

template <typeid X>
concept some_trait {
};
template<class T> someClass where {some_trait<T>} /* class def follows */

The {} after the where clause is a set of predicates requiring specific concepts be supported by the class T. Of course, we have to define how a concept is defined in terms of valid types and operations. This could be like this:

template <typeid X>
concept some_trait {
typename X::iterator;
X operator++(X);
};

So, this means the class argument to someClass must support the increment operator and have a type in its namespace named iterator.

Very useful indeed.

Further information is available on the open-std.org site and at J Siek's publications page.