49

This doesn't compile:

template<class X> struct A {
   template<int I> void f() {}
};

template<class T> void g()
{
   A<T> a;
   a.f<3>();  // Compilation fails here (Line 18)
}

int main(int argc, char *argv[])
{
   g<int>();  // Line 23
}

The compiler (gcc) says:

hhh.cpp: In function 'void g()':

hhh.cpp:18: error: expected primary-expression before ')' token

hhh.cpp: In function 'void g() [with T = int]':

hhh.cpp:23: instantiated from here

hhh.cpp:18: error: invalid use of member (did you forget the '&' ?)

Can anyone explain why this is? Is there a way to get it to work?

Community
  • 1
  • 1
Ari
  • 3,460
  • 3
  • 24
  • 31

1 Answers1

85

Try the following code:

template<class T> void g()
{
   A<T> a;
   a.template f<3>();  // add `template` keyword here
}

According to C++'03 Standard 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.

Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • 5
    This link also explains why: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/keyword_template_qualifier.htm – Björn Pollex Dec 03 '09 at 14:47
  • 11
    well spotted - I'm always forgetting that one. The fact that VC++ lets it past without doesn't help – philsquared Dec 03 '09 at 14:48
  • 6
    Well... Who woulda thunk it! I've never seen this syntax before. Thanks. – Ari Dec 03 '09 at 14:54
  • 1
    Future standards (C++0x) still require `template` here. Some compilers are just not standard's conforming (VC++). – Johannes Schaub - litb Dec 03 '09 at 22:42
  • Yes, it still there. Found it in draft n2857. – Kirill V. Lyadvinsky Dec 04 '09 at 06:02
  • I tried the code with comeau online compiler, which accepts it even in the strictest settings: What happened is that it apparently optimized away the local object and didn't care. If you call `return a.f<3>();` instead (and make it return something), it will error out too. This looks like a optimizer bug to me. – Johannes Schaub - litb Dec 04 '09 at 11:05
  • Strange to hear that. I've tried Comeau and it gives the error `line 8: error: expected an expression`. – Kirill V. Lyadvinsky Dec 04 '09 at 12:03
  • Notice the weird wording of "explicitly depends". In early pre-standard drafts, names could explicitly and implicitly depend on template arguments. Nowadays, there is no such difference anymore, but the "explictly" is still apparent in some places :) – Johannes Schaub - litb Mar 10 '10 at 14:29
  • Furture Standard will not require it only when the template can be looked up already ("member of the current instantiation"). If you do `template struct A { template void f(); void g() { this->f(); } };` then it will go fine because `f` is a "member of the current instantiation" (but only in C++0x, not in C++03). – Johannes Schaub - litb Mar 10 '10 at 14:41