C++ – Why are C++ template error messages so horrific

cerror messagespythontemplates

C++ templates are notorious for generating long, unreadable error messages. I have a general idea of why template error messages in C++ are so bad. Essentially, the problem is that the error isn't triggered until the compiler encounters syntax that is not supported by a certain type in a template. For example:

template <class T>
void dosomething(T& x) { x += 5; }

If T doesn't support the += operator, the compiler will generate an error message. And if this happens deep within a library somewhere, the error message might be thousands of lines long.

But C++ templates are essentially just a mechanism for compile-time duck typing. A C++ template error is conceptually very similar to a runtime type error that might occur in a dynamic language like Python. For example, consider the following Python code:

def dosomething(x):
   x.foo()

Here, if x doesn't have a foo() method, the Python interpreter throws an exception, and displays a stack trace along with a pretty clear error message indicating the problem. Even if the error isn't triggered until the interpreter is deep inside some library function, the runtime-error message still isn't anywhere near as bad as the unreadable vomit spewed by a typical C++ compiler. So why can't a C++ compiler be more clear about what went wrong? Why do some C++ template error messages literally cause my console window to scroll for over 5 seconds?

Best Answer

Template error messages may be notorious, but are by no means always long and unreadable. In this case, the entire error message (from gcc) is:

test.cpp: In function ‘void dosomething(T&) [with T = X]’:
test.cpp:11:   instantiated from here
test.cpp:6: error: no match for ‘operator+=’ in ‘x += 5’

As in your Python example, you get a "stack trace" of template instantiation points, and a clear error message indicating the problem.

Sometimes, template-related error messages can get much longer, for various reasons:

  • The "stack trace" might be much deeper
  • The type names might be much longer, as templates are instantiated with other template instantiations as their arguments, and displayed with all their namespace qualifiers
  • When overload resolution fails, the error message might contain a list of candidate overloads (which might each contain some very long type names)
  • The same error may be reported many times, if an invalid template is instantiated in many places

The main difference from Python is the static type system, leading to the necessity of including the (sometimes long) type names in the error message. Without them, it would sometimes be very difficult to diagnose why the overload resolution failed. With them, your challenge is no longer to guess where the problem is, but to decipher the hieroglyphics that tell you where it is.

Also, checking at runtime means that the program will stop on the first error it encounters, only displaying a single message. A compiler might display all the errors it encounters, until it gives up; at least in C++, it should not stop on the first error in the file, since that may be a consequence of a later error.

Related Topic