When do we need a .template construct
-
29-09-2019 - |
Question
I made the following program
#include <iostream>
#include <typeinfo>
template<class T>
struct Class
{
template<class U>
void display(){
std::cout<<typeid(U).name()<<std::endl;
return ;
}
};
template<class T,class U>
void func(Class<T>k)
{
k.display<U>();
}
int main()
{
Class<int> d;
func<int,double>(d);
}
The above program doesn not compile because display()
is a template member function so a qualification of .template
before display()
must be done. Am I right?
But when I made the following program
#include <iostream>
#include <typeinfo>
template<typename T>
class myClass
{
T dummy;
/*******/
public:
template<typename U>
void func(myClass<U> obj);
};
template<typename T>
template<typename U>
void myClass<T>::func(myClass<U> obj)
{
std::cout<<typeid(obj).name()<<std::endl;
}
template<class T,class U>
void func2(myClass<T>k)
{
k.template func<U>(k); //even it does not compile
}
int main()
{
myClass<char> d;
func2<char,int>(d);
std::cin.get();
}
Why k.func<char>(k);
does not compile even after giving a .template
construct?
Solution
The <
symbol means both "less than" and "begin template arguments." To distinguish between these two meanings, the parser must know whether the preceding identifier names a template or not.
For example consider the code
template< class T >
void f( T &x ) {
x->variable < T::constant < 3 >;
}
Either T::variable
or T::constant
must be a template. The function means different things depending which is and which isn't:
- either
T::constant
gets compared to 3 and the Boolean result becomes a template argument toT::variable<>
- or
T::constant<3>
gets compared tox->variable
.
The to disambiguate, the template
keyword is required before either variable
or constant
. Case 1:
template< class T >
void f( T &x ) {
x->template variable < T::constant < 3 >;
}
Case 2:
template< class T >
void f( T &x ) {
x->variable < T::template constant < 3 >;
}
It would be kind of nice if the keyword were only required in actual ambiguous situations (which are kind of rare), but it makes the parser much easier to write and it prevents such problems from catching you by surprise.
For standardese, see 14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
OTHER TIPS
Section 5.1 of C++ Templates explains this construct in detail
The below function has a problem
template<class T,class U>
void func2(myClass<T> k)
{
k.template func<U>(k); //even it does not compile
}
Here T = char and U = int
myclass<char>::func<int>(myclass<char>)
is being called. However such a function does not exist
Even though in normal circumstances 'char' is convertible to 'int', this does not hold good for explicitly specified template arguments
The standard requires the template
or typename
keywords to disambiguate things that depend on the template context.
The first example compiles and runs fine for me in VS 2010.