15

The following code will not compile with G++ 4.5 or 4.6 (snapshot). It will compile with the Digital Mars Compiler 8.42n.

template <int I>
struct Foo {
  template <int J>
  void bar(int x) {}
};

template <int I>
void test()
{
  Foo<I> a;
  a.bar<8>(9);
};

int main(int argc, char *argv[]) {
  test<0>();
  return 0;
}

The error message is:

bugbody.cpp: In function 'void test() [with int I = 0]':
bugbody.cpp:16:11:   instantiated from here
bugbody.cpp:11:3: error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'

Is the program valid C++?

user2023370
  • 10,488
  • 6
  • 50
  • 83
  • possible duplicate of [C++ template member function of template class called from template function](http://stackoverflow.com/questions/1840253/c-template-member-function-of-template-class-called-from-template-function) – Kirill V. Lyadvinsky May 04 '11 at 11:22
  • possible duplicate of [Where and why do I have to put "template" and "typename" on dependent names?](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-template-and-typename-on-dependent-names) – Mike Seymour May 04 '11 at 11:43

1 Answers1

34

Since the bar in a.bar is a dependent name, the compiler doesn’t know that it’s a template. You need to specify this, otherwise the compiler interprets the subsequent <…> as binary comparison operators:

a.template bar<8>(9);

The compiler behaves correctly.

The reason for this behaviour lies in specialisation. Imagine that you have specialised the Foo class for some value:

template <>
struct Foo<0> {
    int bar;
};

Now your original code would compile, but it would mean something completely different. In the first parsing pass, the compiler doesn’t yet know which specialisation of Foo you’re using here so it needs to disambiguate between the two possible usages of a.bar; hence the keyword template to show the compiler that the subsequent <…> are template arguments.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Thanks, and a nice answer; I clearly need to hit the books. How does your specialisation allow the original `a.bar<8>(9)` to work? Is it now the method `bar`, or int `bar` which is referenced? – user2023370 May 04 '11 at 11:25
  • Oh my! It sees the `<` and `>` as less than and greater than operators! With your specialisation, it sees it as: `(a.bar) < (8 > 9)` – user2023370 May 04 '11 at 11:33
  • 2
    @user643722 Actually, it’s `(a.bar < 8) > 9` (operators are left associative). But yes, that’s it. – Konrad Rudolph May 04 '11 at 11:47