views:

89

answers:

1

Hello everybody. I'm porting my c++ windows code (msvc & intel) to Linux (g++). The code uses lots of templates (I like metaprogramming ;-). But I can't compile this code:

template <class TA>
struct A
{
    template <class TAB> struct B;
};


template <class TC>
struct C {};


template <class TD>
struct D
{
    template <class TTD> class T {};
};


template<class TA>
    template<class TBA>
struct A<TA>::B : C<typename D<TA>::T<TBA> >
{
    int foo;
};

g++ tells me that in definition of A::B, C class has invalid template arguments. But on msvc and intel it works well! What's the problem here? PS: Sorry, I can't post the original code, because it's too template-complicated. But this example is virtually the same and gives the same error on g++. Thank you.

UPDATE: I've found the problem is in TBA argument of T. g++ doensn't like usage of second template in the definition.

+8  A: 

You need the template keyword

template<class TA>
    template<class TBA>
struct A<TA>::B : C<typename D<TA>::template T<TBA> >
{
    int foo;
};

GCC is correct to give a diagnostic here. This is because T cannot be looked up in the dependent scope D<TA>. The meaning of the < after it depends on whether T is a template or not. The Standard says that T shall be assumed to be not a template and thus T cannot be followed by a template argument list.

template is like typename in that it tells the compiler to treat T as a template and that the < is the start of an argument list in any case. The Standard says in paragraphs 14.2/2 and 14.2/4

For a template-name to be explicitly qualified by the template arguments, the name must be known to refer to a template.

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.

In your case, you have T appear after the nested-name-specifier D<TA> which depends on the template-parameter TA. For the typename-specifier to parse correctly, the construct D<TA>::T<TBA> must interpret T as the name of a class template, which 14.2 forbids.


On that topic, it's always a good idea to try and compile with Clang

main1.cpp:21:37: error: use 'template' keyword to treat 'T' as a dependent template name
struct A<TA>::B : C<typename D<TA>::T<TBA> >
                                    ^
                                    template 
1 error generated.
Johannes Schaub - litb
BRILLIANT, THANX!
f0b0s
ok, i got it. i thout about second 'typename' keyword, but now a 'template'.
f0b0s
Wow, I really like this diagnostic message, now that's what you expect from the ideal compiler.
Matthieu M.