41

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?

4
  • 8
    Some compilers have horrific error messages, but other are really good (clang++ wink wink). Commented Apr 21, 2011 at 0:53
  • 2
    So you would prefer your programs failing at runtime, shipped, at the hands of a customer, instead of failing at compile-time?
    – P Shved
    Commented Apr 21, 2011 at 5:12
  • 17
    @Pavel, no. This question is not about the advantages/disadvantages of runtime vs compile time error-checking.
    – Channel72
    Commented Apr 21, 2011 at 10:52
  • 2
    As an example of large C++ template errors, FWIW: codegolf.stackexchange.com/a/10470/7174
    – kebs
    Commented Mar 22, 2018 at 12:29

3 Answers 3

35

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.

1
  • 4
    Could you give an example of an error being a consequence of a later error?
    – Ruslan
    Commented May 18, 2018 at 22:18
16

A few of the obvious reasons include:

  1. History. When gcc, MSVC, etc., were new, they couldn't afford to use lots of extra space to store data to produce better error messages. Memory was scarce enough that they just couldn't.
  2. For years, consumers ignored error message quality, so vendors mostly did too.
  3. With some code, the compiler can re-synchronize and diagnose real errors later in the code. Errors in templates cascade so badly that anything past the first is almost always useless.
  4. The general flexibility of templates makes it hard to guess what you probably meant when your code has an error.
  5. Inside a template, the meaning of a name depends on both the context of the template, and the context of the instantiation, and argument dependent lookup can add still more possibilities.
  6. Function overloading can provide lots of candidates for what a particular function call might refer to, and some compilers (e.g., gcc) dutifully list them all when there's an ambiguity.
  7. Many coders who'd never consider using normal parameters without assuring that the passed values meet requirements, don't even attempt to check template parameters at all (and I have to confess, I tend toward this myself).

That's far from exhaustive, but you get the general idea. Even if it isn't easy, most of it can be cured. For years, I've been telling people to get a copy of Comeau C++ for regular use; I've probably saved enough from one error message one time to pay for the compiler. Now Clang is getting to the same point (and it's even less expensive).

I'll close with a general observation that sounds like a joke, but really isn't. Most of the time, a compiler's real job honestly is to turn source code into error messages. It's high time that vendors concentrated on doing that job a bit better -- though I'll openly admit that when I've written compilers, I had a strong tendency toward treating it as secondary (at best) and in some cases almost ignored it completely.

2
  • Wikipedia says Comeau is probably not being updated any more
    – qwr
    Commented Mar 23, 2022 at 21:12
  • @qwr: Yes, I believe that's true nowadays. In fact, I'm not at all sure you can buy a copy even if you want to (but I'll admit I'm not sure you can't either). Fortunately, gcc and clang have improved a lot since. Commented May 3, 2023 at 22:04
9

The simple answer is, because Python was designed to work that way, whereas a lot of the stuff associated with templates came about by accident. It was never intended to become a Turing-complete system unto itself, for example. And if you can't deliberately plan and reason about what happens when your system works, why should anyone expect careful, thoughtful planning about what happens when something goes wrong?

Also, as you pointed out, the Python interpreter can make it a lot easier on you by displaying a stack trace because it's interpreting Python code. If a C++ compiler hits a template error and gives you a stack trace, that would be just as unhelpful as "template vomit," wouldn't it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.