2

My C++ code is below:

//test.cpp
#include <iostream>
using namespace std;

template <int SIZE, class T>
struct A
{
    void g(int x, const T& t)
    {
        t.f<SIZE>(x);
    }
};

struct B
{
    template <int SIZE>
    void f(int x) const
    {
        cout << SIZE << ": " << x << endl;
    }
};


int main(void)
{
    A<3, B> a;
    B b;
    a.g(9, b);
    return 0;
}

I got a surprising error when compiled it with g++(version is 4.8.2):

test.cpp: In instantiation of ‘void A<SIZE, T>::g(int, const T&) [with int SIZE = 3; T = B]’:
test.cpp:27:13:   required from here
test.cpp:9:12: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
         t.f<SIZE>(x);
            ^

Why it take < as operator< rather than a mark to enclose the template argument?

Yantao Xie
  • 12,300
  • 15
  • 49
  • 79

2 Answers2

7

Because the code is inherently ambiguous1 so the compiler has to decide either way. And it was arbitrarily decided by the C++ standards committee that if in doubt, assume that a name is a variable, not a type.

If you want your code to be parsed as a template, you need to say so explicitly:

t.template f<SIZE>(x);

1 At the time where this code is parsed, the type of t is not yet known since it’s a template. Consider the following type:

struct T {
    int f;
};

If you now instantiate A with that type, you get (pseudocode since the template is instantiated):

void A<3, T>::g(int x, T const& t) {
    ((t.f) < 3) > x;
}

I’ve added parentheses for clarification: this is how the compiler sees your code, and it’s entirely valid (although nonsensical).

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
4

Let's look at:

t.f < SIZE > (x);

Whitespace is not significant. If t.fis a variable this could be saying: Do t.f < SIZE and then do (that result) > x.

Further, the compiler doesn't know yet whether t.f is a variable or a function template. Remember that templates can be specialized, so even if it seems that t.f is a function template now; later on in the piece this code could be instantiated from a specialization of B where t.f is a variable.

To resolve this dilemma, names which are ambiguous are treated as variable names unless you specifically indicate that they are something else. In this case that's done by writing t.template f ; a similar principle has us write typename T::iterator when T is a dependent name.

M.M
  • 138,810
  • 21
  • 208
  • 365