3

Why doesn't this code compile?

struct A {
    template <class T>
    static T a(int i) { return 2*i; }
};

template <class T>
struct B {
    double b;
    B(): b(T::a<double>(5)) {}
};

template class B<A>;

The compiler doesn't even reach the template instantiation. I'm using gcc 4.7.0.

test.cc: In constructor »B<T>::B()«:
test.cc:9:25: Error: expected »(« before »<« token
test.cc:9:26: Error: expected primary-expression before »double«
Zeta
  • 103,620
  • 13
  • 194
  • 236
Tom De Caluwé
  • 926
  • 5
  • 17

3 Answers3

6

You're missing a template keyword since a is a dependent name (or something like that).

B(): b(T::template a<double>(5)) {}

(Also your last line should be template struct B<A>;.)

For the gory details, see: Where and why do I have to put the "template" and "typename" keywords?

Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
2

You have to put template before the method name:

B(): b(T::template a<double>(5)) {}

This is because when the template class B is being parsed, the compiler does not know that T::a is a templated method (since T is not specified until then, and T::a is completely unknown), so it doesn't know that <double> should be parsed as a template parameter list.

It could also mean and will indeed be parsed as: T::a less than double greater than (0). Of course, double isn't an expression, so this failes; thus the error message. So the compiler could just assume that you want it to be a templated function call. But you can also have a non-type template parameter, let's say for example an int, so T::a<42>(5) can be parsed as T::a less than 42 greater than (5), which isn't a template. But you wanted it to be parsed as T::a then a template parameter list with the parameter 42 and then the call-operator with an argument 5.

To tell the compiler that it's a templated function call, you have to put template before the function name.

leemes
  • 44,967
  • 21
  • 135
  • 183
0

The compiler knows nothing about T. So every time you write T::{something} it assumes, that {something} is either a member variable or method of T. If it's not, you have to tell it what it is. You probably know about the typename keyword you have to use if what you are referring to is a type and not a variable. There's a similar trick for template members:

template <class T>
struct B {
    double b;
    B(): b(T::template a<double>(5)) {}
};

Now the compiler knows a is a template and that what comes after that is the template parameter list.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90