gexicide
gexicide

Reputation: 40058

C++ Strange Compiler Syntax Error

I got the following code (do not argue about whether it is meaningful, it is just a minimal example):

struct X{
    template <typename T>
    T foo(){ return T(); }
};

template <typename T>
struct Z{
    virtual X bar(){
        bar().foo<int>();
        return X();
    }
};

It does not compile on my g++4.6.3. The line bar().foo<int>(); gives the following error:

error: expected primary-expression before ‘int’
error: expected ‘;’ before ‘int’

when I first save the result of bar() in a local variable, then it works, i.e. if I replace bar().foo<int>() by

        X x = bar();
        x.foo<int>(); 

then it works. If i now declare the local variable auto instead of X, i.e.:

        auto x = bar();
        x.foo<int>();

then I receive the same error as before. If I remove the type parameter from class Z (i.e. make it a usual instead of a template class), then it works again.

If I use a classtype like X instead of int as type parameter for foo, i.e. foo<X>, then I receive the following error instead:

expected primary-expression before ‘>’ token
expected primary-expression before ‘)’ token

I am really unable to spot the error here. Please help!

Upvotes: 2

Views: 397

Answers (1)

eq-
eq-

Reputation: 10096

You need to qualify that the type in question is templatable (this is a work-around for what I think is a bug in GCC, see edit below), i.e.

struct X{
    template <typename T>
    T foo(){ return T(); }
};

template <typename T>
struct Z{
    virtual X bar(){
        bar().template foo<int>();
        return X();
    }
};

The basic issue has to do with parsing, because explicit template instantiations could be parsed in a number of ways. The interesting bit (I think) is located in 14.2p4, and it is as follows:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object or pointer expression of the postfix-expression or the nested-name-specifier in the qualified-id depends on a template parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

If I'm not gravely mistaken, Z<T>::bar does depend on a template parameter, but at the same time it does refer to the current instantiation, thus I'm inclined to believe that the standard does not require a qualification like GCC does. When multiple compilers have conflicting results, I tend to side with Comeau, which in this case says that the template qualifier is not necessary.

Upvotes: 8

Related Questions