Template Metaranting
Posted on by Idorobots
Here's another post in the series, this time it's C++ vs. the D programming language.
Let's talk about templates. If you've ever tried templates in C++ you surely as hell recall the pages and PAGES of compiler errors and seemingly random placement of typename
keyword. Trust me, there are EVEN WORSE problems with templates in C++... Consider the following:
struct Foo {
template<int N>
void bar() {}
template<int N>
struct Bar {};
};
template<typename T>
void f() {
T foo;
foo.template bar<0>(); // Line 12
typename T::template Bar<0> b; // Line 13
}
int main() {
f<Foo>();
}
Line 12 shows the so-called object.template function<arg>()
syntax and it is probably the least known C++ syntax out there. The reason it exists is simple - in this particular corner case the compiler simply... can't... parse... this code. When parsing f()
functions definition it can't possibly know that T foo
has a templated member bar
and confuses the template opening bracket with the less-than operator, so we end up with an unresolved overloaded function type
error. That's harsh.
Line 13 contains a similar corner case where we need to use all kinds of messed up syntax just to declare a variable. The typename
tells the compiler that we want a type because you know, it won't figure it out on its own. Next, we access with a ::
the templated member type Bar
instantiated with a 0. The template
is there for the same reason it's found on line 12.
Here's the semantically equivalent code in the D programming language:
struct Foo {
void bar(int N)() {}
struct Bar(int N) {}
}
void f(T)() {
T foo;
foo.bar!0(); // Line 9
T.Bar!0 b; // Line 10
}
void main() {
f!Foo();
}
The analogous lines (9 & 10) will always mean the same and don't require disambiguation with any keywords.
C++' template problem may not seem that serious, but imagine more complicated templates and, oh snap, debugging their code and all the weird stuff that happens when you forget a random =template= keyword somewhere. And I didn't even start ranting about...1
// ...C++11.
template <size_t k, class T, class... Ts>
typename enable_if<k != 0, typename tuple_element<k, tuple<T, Ts...>>::type&>::type // WAT
get(tuple<T, Ts...>& t) {
tuple<Ts...> & super = t;
return get<k - 1>(super);
}
To sum it up, D's template syntax is simpler, corner cases don't exist 2 and declarations are cleaner. This is a yet another reason I like D so much.
2016-02-16: Adjusted some links & tags.
- The snippet comes from an awesome presentation given by Andrei Alexandrescu on the Going Native 2012 conference a while ago.
I didn't get into any details because it's a topic for another rant. Stay tuned.↩ - Don't quote me on that one.↩