Reputation: 40058
I got the following code (do not argue about whether it is meaningful, it is just a minimal example):
struct X{
template <typename T>
T foo(){ return T(); }
};
template <typename T>
struct Z{
virtual X bar(){
bar().foo<int>();
return X();
}
};
It does not compile on my g++4.6.3. The line bar().foo<int>();
gives the following error:
error: expected primary-expression before ‘int’
error: expected ‘;’ before ‘int’
when I first save the result of bar() in a local variable, then it works, i.e. if I replace bar().foo<int>()
by
X x = bar();
x.foo<int>();
then it works. If i now declare the local variable auto
instead of X
, i.e.:
auto x = bar();
x.foo<int>();
then I receive the same error as before. If I remove the type parameter from class Z (i.e. make it a usual instead of a template class), then it works again.
If I use a classtype like X
instead of int
as type parameter for foo, i.e. foo<X>
, then I receive the following error instead:
expected primary-expression before ‘>’ token
expected primary-expression before ‘)’ token
I am really unable to spot the error here. Please help!
Upvotes: 2
Views: 397
Reputation: 10096
You need to qualify that the type in question is templatable (this is a work-around for what I think is a bug in GCC, see edit below), i.e.
struct X{
template <typename T>
T foo(){ return T(); }
};
template <typename T>
struct Z{
virtual X bar(){
bar().template foo<int>();
return X();
}
};
The basic issue has to do with parsing, because explicit template instantiations could be parsed in a number of ways. The interesting bit (I think) is located in 14.2p4, and it is as follows:
When the name of a member template specialization appears after
.
or->
in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object or pointer expression of the postfix-expression or the nested-name-specifier in the qualified-id depends on a template parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keywordtemplate
. Otherwise the name is assumed to name a non-template.
If I'm not gravely mistaken, Z<T>::bar
does depend on a template parameter, but at the same time it does refer to the current instantiation, thus I'm inclined to believe that the standard does not require a qualification like GCC does. When multiple compilers have conflicting results, I tend to side with Comeau, which in this case says that the template
qualifier is not necessary.
Upvotes: 8