I think you should use like this:
A<T>::template f<0>();
If you write like this A<T>::f<0>(); It is ambiguous for compiler, it can not deduce surely that f is a template function in template class A, it may take it as ((A<T>::f) < 0) >(), and would not compile correctly, the additional template is suggested to compiler that f is a template function.
It is the same case when we use typename like this:
class A {
typename B::IntType *i;
};
On line 23, its a function call, but what is T here? The T refers to the parameter in the second template. In other words the scope of the T in the first template ends on line 18. The other problem is that A::f<0>() and A::f<1>() are different types, so that might be why it is rejected.
Line 25 Maybe that is to do with template argument deduction. g() is a static function with no arguments returning void, so that is ok, only because it didn't have it's own template parameter like f() does.
Line 26 works because you have specified the int (The T in the first template )
Line 27 works because it doesn't involve T , the 0 specifies the int, so everything is known.
Btw there is no need to specify void for a function with no parameters, this has never been a requirement for C++, instead it's something C programmers do.