7

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?)

Community
  • 1
  • 1
Dan Nissenbaum
  • 13,558
  • 21
  • 105
  • 181
  • 3
    Test it against gcc to create a majority! :-) I _think_ clang is right in requiring the `template` keyword. – Dietmar Kühl Dec 30 '13 at 21:13
  • 6
    Rule of thumb: if VS disagrees with another compiler, then VS is wrong. This is accurate to about 90-95%. –  Dec 30 '13 at 21:14
  • GCC agrees with clang. –  Dec 30 '13 at 21:14
  • 4
    In particular with respect to templates and lookup, VS has a tendency not to get it right as it has been dependent on single lookup (rather than two phase lookup) for a long period of time – David Rodríguez - dribeas Dec 30 '13 at 21:15

2 Answers2

7

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].

Community
  • 1
  • 1
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    For fairness with VC++, this is a Standard defect because the grammar makes the code that has the "template" in it ill-formed. See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1710 – Johannes Schaub - litb Dec 31 '13 at 01:44
  • I should also comment on Richard's sayings in the DR "although the relevant wording in 14.2 [temp.names] paragraph 4 only requires it in a qualified-id, not in a class-or-decltype". Often it is the case that the Standard refers to qualified-id, when it actually means something like "qualified name". See https://groups.google.com/forum/#!msg/comp.lang.c++.moderated/_DrR6f-92Yg/yw5te3CMHW8J and https://groups.google.com/forum/#!topic/comp.std.c++/q1kk9ekIJXI – Johannes Schaub - litb Dec 31 '13 at 01:59
  • Funny, here's an old dupee of 1710: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#314 – Johannes Schaub - litb Dec 31 '13 at 02:03
5

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.

Casey
  • 41,449
  • 7
  • 95
  • 125