[c++0x] Considering better error messages for templates.

Germán Diago germandiago@gmail.com
Thu Dec 10 23:01:00 GMT 2009


Hello. Looking at a (fantastic) blog, I came up with this and I think
it should be useful to considerate it when implementing
c++0x libraries. We all know that template errors are very
frustrating. So there is a technique here which would work great.


The C++0x features decltype, static_assert and the "new function
declarator syntax" can be combined with our old friend SFINAE to
generate nicer template compile errors.

As a simple example, consider a container class similar to std::set.
Normally if you just declare a variable

set<my_type> s;

it will compile without error even if my_type has no operator<. You
will only get an error when you try to call a set member function,
such as insert(). Worse still, the errors tend to be quite verbose.
(Too verbose for me to want to paste here, anyway.) It would be really
nice to generate a short, readable error at the point of the original
variable declaration. Let's see how we can do just that in C++0x.

First, we need to write a compile-time test for operator<. This is
where SFINAE, decltype and the new function declarator syntax come
together. We write the test function:

auto less_than_test(const T* t)
  -> decltype(*t < *t, char(0));

and the fallback overload:

std::array<char, 2> less_than_test(...);

The trick here is that, according to the C++0x grammar, we have:

decltype ( expression )

and

expression:
    assignment-expression
    expression , assignment-expression

This means that the first overload uses decltype to do two things: it
makes the overload a viable candidate only if the expression *t < *t
is valid; and it says the overload returns a char.

Second, we can use sizeof to determine which of the overloads is
selected for a given type T, and static_assert to generate a readable
error:

template <typename T>
class set
{
public:
  static_assert(
      sizeof(less_than_test((T*)0)) == 1,
      "type T must provide operator<");
};

The g++ 4.4 compiler then gives the following output on the original
variable declaration:

test.cpp: In instantiation of set<my_type>
test.cpp:21:   instantiated from here
test.cpp:13: error: static assertion failed:
    "type T must provide operator<"

It works with function templates too.



More information about the Libstdc++ mailing list