2

The following minimal example put in a .cpp file causes a compiler error in VisualStudio 2017 (15.7.4, with /std:c++17 enabled):

template <typename T>
class A
{
    void f(T& t)
    {
        t.g<2>();
    }
};

// B is a candidate for the template parameter T in A
struct B {
    template <int a>
    void g() {
        // nothing here
    }
};

The compiler error refers to the body of A::f() and reads:

error C2760: syntax error: unexpected token ')', expected 'expression' .

Note that neither A nor B are actually instantiated. The same error also occurs without declaring B.

However, if I switch the order in which A and B are declared, the example compiles (and A can be instantiated). This is surprising, because I have not expressed any relation between A and B in the code. Another surprising fact is that adding an argument (e.g. an int) to the signature of B::g() and the call of g() also seems to solve the error (without changing the order of declaration).

My questions are: (1) Why does the code above produce a compiler error? (2) How I can resolve it in a clean way?

Peter H
  • 475
  • 5
  • 14
  • 2
    Try `t.template g<2>();`. – songyuanyao Jul 27 '18 at 08:00
  • It is true that the explanation and fix in the linked question also fixes my example code above (see also the accepted answer). I am still not quite sure about the weird behavior when switching the order of declarations in my example. Also, that duplicate may be hard to find if you do not already have an educated guess about the cause of the problem. Still, I agree it is closely related and may be considered a duplicate. I will mark it as such. – Peter H Jul 27 '18 at 08:39
  • The order wouldn't matter except on MSVC. Its handling of templates has been non-standard compliant for decades. Only recently did they introduce a more correct implementation. But you need to opt-into it. It's not on by default even in new projects. – StoryTeller - Unslander Monica Jul 27 '18 at 08:41
  • 1
    Here's the relevant blog post, if you want to learn more https://blogs.msdn.microsoft.com/vcblog/2017/09/11/two-phase-name-lookup-support-comes-to-msvc/ – StoryTeller - Unslander Monica Jul 27 '18 at 08:42

1 Answers1

5

If you use a template in an template class, you have to tell the compiler that this is a template.

template <typename T>
class A
{
    void f(T& t)
    {
        t.template g<2>();
    }
 };

A good explanation about the .template and ::template usage can be found here: Where and why do I have to put the "template" and "typename" keywords?

Klaus
  • 24,205
  • 7
  • 58
  • 113