24

This is a minimal test case of some code that I actually have. It fails when it tries to evaluate a.getResult<B>():

test.cpp: In function 'void printStuff(const A&)':
test.cpp:6: error: expected primary-expression before '>' token
test.cpp:6: error: expected primary-expression before ')' token

The code is:

#include <iostream>

template< class A, class B>
void printStuff( const A& a)
{
    size_t value = a.getResult<B>();
    std::cout << value << std::endl;
}

struct Firstclass {
    template< class X >
    size_t getResult() const {
        X someInstance;
        return sizeof(someInstance);
    }
};

int main(int, char**) {
    Firstclass foo;

    printStuff<Firstclass, short int>(foo);
    printStuff<Firstclass, double>(foo);

    std::cout << foo.getResult< double >() << std::endl;

    return 0;
}

If I comment out the printStuff function and where it's called, the foo.getResult< double >() call compiles fine and does what is expected.

Any idea what's going on? I've been working with extensively templated code for a while and have never encountered anything like this.

Seth Johnson
  • 14,762
  • 6
  • 59
  • 85

2 Answers2

42

When you refer to a template that is a member of dependent type, you have to prepend it with a keyword template. This is how the call to getResult inside printStuff should look

size_t value = a.template getResult<B>();

This is similar to using the keyword typename when referring to nested typenames in a dependent type. For some reason, the bit about typename with nested types is rather well-known, but the similar requirement for template with nested templates is relatively unknown.

Note that the general syntax structure is a bit different though. The typename is always put in front of the full name of the type, while template is inserted in the middle.

Again, this is only necessary when you are accessing a template member of a dependent type, which in the above example would be A in printStuff. When you call foo.getResult<> in main the type of foo is not dependent, so there's no need to include the template keyword.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 10
    Thanks! That's the most bizarre syntax I've ever seen in C++. – Seth Johnson Nov 05 '09 at 19:17
  • 3
    Somehow VC++ is quite lenient about it (ie, you can often get away without it), but gcc is definitely not! – Matthieu M. Nov 06 '09 at 07:15
  • Totally agree with you guys on all three points, except I found gcc to also be lenient until cross-compiling for ARM with CodeSourcery. – DataGraham Oct 19 '11 at 13:32
  • wow, I thought I knew everything about C++ syntax as well; I've co-written a C++ front-end and I didn't know this – Daniel Jun 23 '15 at 02:43
  • Good if the error message produced by GCC could be a little bit descriptive about the missing keyword. Even with GCC10 if i forget the template keyword, I receive 'error: expected primary-expression before '>' token', which does not help in any way... if it could be something like 'expecting 'template' before a templated function call' – Nuclear May 31 '22 at 06:45
10

Your code is ill-formed according to C++ 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.

So, you should write size_t value = a.template getResult<B>();

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212