Amazing feats of Clang Error Recovery
blog.llvm.org
blog.llvm.org
The merge conflict marker recognition at the end actually brought a smile to my face. I would be very happy if my products would produce such a reaction in my customers.
For people not doing template meta-programming, I agree using the typedefs is better. But even if you're just using a library that makes use of template metaprogramming - such as uBlas - it could help you figure out why you're using it wrong.
gcc error outputs are remnants of a bygone era where your brain contained the source of the compiler and the entire language specification. You are supposed to feel bad when you fail to please the parser (you wrote the entire compiler suite and implemented the language spec yourself after all, didn't you?).
Clang error messages softly whisper sweet nothings of suggestions and encouragement. You effortlessly resolve your typos and misconceptions. Before you know it, you're back into Productive Working Land having circumnavigated ancient realms of error messages from the past 20 years.
For example (t.cc):
template <typename C>
void test (C c) { C::iterator it = begin(); }
⋮
test(std::vector<int>());
Shows this error (with a note about what the programmer likely meant): t.cc: In function ‘void test(C)’:
t.cc:2: error: expected `;' before ‘it’
t.cc: In function ‘void test(C) [with C = std::vector<int, std::allocator<int> >]’:
t.cc:7: instantiated from here
t.cc:2: error: dependent-name ‘C::iterator’ is parsed as a
non-type, but instantiation yields a type
t.cc:2: note: say ‘typename C::iterator’ if a type is meantThey are no useless, you just have to remember which combination of messages having nothing to do with your code could be caused by what sort of errors.
Gcc makes sure we will remember these rules better by making it painful and thus more vivid in memories.
Also - real fun begins, when you forgot semicolon after the class definition in your header, and error shows in different file.
When I'm using a language, alarm bells ring when I find myself needing to type something like :
std::vector<char> v(std::istream_iterator<char>(ifs), std::istream_iterator<char>());
With C++ most of the time, one is either consuming a huge/important library (even an OS SDK) or writing one. If you're consuming the librarie(s), you just can't go around typedefing important APIs, or you will end up maintaining a nightmare of a fork. And if you're writing one, the sensible thing to do is to stick with a tangible subset of C++, like most good libraries do.
Seriously, if your C++ code starts to look ugly, you're probably using the language to its full potential. Don't do that. Scale back to a manageable C-like subset; And no, you can't grow your C++ code-base to a blissful Greenspun-esque nirvana; more C++ begets, well, MORE C++. Those multi-page Doxygen class listings and woolly dependency diagrams never gel and mesh into something organic. The code-base just grows diagonally, and orthogonal to your intended direction..
To the Clang team, this is damn impressive. I've never thought about a compiler detecting merge conflicts, but thats pretty cool.