C++ template WTF
by Leandro Lucarella on 2010- 07- 25 23:22 (updated on 2010- 07- 25 23:22)- with 0 comment(s)
See this small program:
template<typename T1>
struct A {
template<typename T2>
void foo_A() {}
};
template<typename T>
struct B : A<T> {
void foo_B() {
this->foo_A<int>(); // line 10
}
};
int main() {
B<int> b;
b.foo_B();
return 0;
}
You may think it should compile. Well, it doesn't:
g++ t.cpp -o t t.cpp: In member function ‘void B<T>::foo_B()’: t.cpp:10: error: expected primary-expression before ‘int’ t.cpp:10: error: expected ‘;’ before ‘int’
Today I've learned a new (horrible) feature of C++, foo_A is an ambiguous symbol for C++. I've seen the typename keyword being used to disambiguate types before (specially when using iterators) but never a template. Here is the code that works:
template<typename T1>
struct A {
template<typename T2>
void foo_A() {}
};
template<typename T>
struct B : A<T> {
void foo_B() {
this->template foo_A<int>();
// ^^^^^^^^
// or: A<T>::template foo_A<int>();
// but not simply: template foo_A<int>();
}
};
int main() {
B<int> b;
b.foo_B();
return 0;
}
Note how you have to help the compiler, explicitly saying yes, believe me, foo_A is a template because it has no clue. Also note that the template keyword is only needed when A, B and A::foo_A are all templates; remove the template<...> to any of them, and the original example will compile flawlessly, so this is a special special special case.
Yeah, really spooky!
In D things are more natural, because templates are not ambiguous (thanks to the odd symbol!(Type) syntax), you can just write:
class A(T1) {
void foo_A(T2)() {}
}
class B(T) : A!(T) {
void foo_B() {
foo_A!(int)();
}
}
void main() {
B!(int) b;
b.foo_B();
}
And all works as expected.