Clang (OS X) requires “template” keyword in a part

2019-02-09 17:26发布

问题:

I am writing a cross-platform application in two compilers (Clang on Xcode v5.0.2, and Visual Studio 2012 Update 4) and I have run into a scenario in which the two compilers disagree about the required syntax for the use of the template keyword in a nested declaration.

Here is the code (boiled down to an easily reproducible test case):

template<typename T>
struct Base
{
    template<typename U>
    struct InnerBase
    {};
};

template<typename T, typename U>
struct Derived : public Base<T>
{
    // the "template" keyword is REQUIRED in Clang/OSX
    struct InnerDerived : public Base<T>::template InnerBase<U>
    {};

    // the "template" keyword is FORBIDDEN in Visual Studio 2012
    struct InnerDerived : public Base<T>::InnerBase<U>
    {};
};

int main()
{
    Derived<int, int>::InnerDerived foo;
}

As noted, the two compilers disagree about the use of the "template" keyword.

For Clang, when the template keyword is not included, the error is:

Use 'template' keyword to treat 'InnerBase' as a dependent template name

For Visual Studio, when the template keyword is included, the error is:

'Base::InnerBase' : use of class template requires template argument list

I have looked at various other StackOverflow questions regarding the rules for use of the template keyword (for example, Where and why do I have to put the "template" and "typename" keywords?). However, looking at this, and other similar questions, does not give me confidence in claiming that one compiler is correctly implementing C++11 and that the other is not.

(Note that Clang's error makes sense to me, while the VS error doesn't make much sense to me because it seems that I am including the template argument list.)

Which compiler is correct in this case? Should the template keyword be included, or not, in the sample code above (for C++11 compliance)?

(Possibly I have not set the compiler settings correctly to use C++11 in one or the other case - in which case, my question still stands: which version of the code above is correct C++11 code?)

回答1:

It seems the relevant clause is 14.2 (temp.names) paragraph 4:

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 expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.

I think that says that template is required. Following up with DyP's comment, it seems certainly wrong to reject the keyword even if it isn't required (paragraph 5 of the same clause):

A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template. [Note: The keyword template may not be applied to non-template members of class templates. —end note] [Note: As is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the -> or . is not dependent on a template-parameter, or the use does not appear in the scope of a template.—end note].



回答2:

Clang is correct, Base<T> is dependent on a template parameter. This is yet another symptom of Visual C++ not implementing two-phase name lookup for templates.