Why doesn't standard C ++ grammar cover this case?

Basically, I mean the C ++ 03 standard, but, having a quick look at it, it should also be applicable to the C ++ 11 standard.

The following code was compiled and successfully executed in VC ++ 2010:

template<typename T> class CC { public: T f(T a) { return a*a; } }; template<> class ::CC<int> { //<--- ::CC<int> syntax allowed by VC++2010, but is it non-standard ? public: int f(int a) { return a*a; } }; int main(int argc, _TCHAR* argv[]) { ::CC<int> c; } 

Note the syntax ::CC<int> for referencing a template defined in the global namespace. This is not the same as the NamespaceA::CC<int> syntax preceded by the :: operator. With some other tools, I tried to parse this using a grammar strictly from C ++ 03, but it gave me errors, and it seems to me that the standard takes only the form NamespaceA::CC<int> in the declaration of the head of the class.

On closer inspection, the problem is that the class-head is defined by this grammar in the standard:

 class-head: class-key identifier(optional) base-clause(optional) class-key nested-name-specifier identifier base-clause(optional) class-key nested-name-specifier(optional) template-id base-clause(optional) 

And since nested-name-specifier has the form AA::bb:: ..., it does not accept my ::CC . My question is why the C ++ standard does not allow the :: CC form? Is this just my misinterpretation of standard grammar? If the correct grammar looks like this:

 class-head: ... class-key '::'(optional) nested-name-specifier(optional) template-id base-clause(optional) 

Note that the above form is really used by the standard somewhere else, say when specifying the declarator identifier:

 declarator-id: id-expression ::(optional) nested-name-specifier(optional) class-name 
+7
c ++ language-lawyer c ++ 11 c ++ 03 grammar
source share
2 answers

From a comment by Colombo,

Of course, the naming specifier may be ::, and CC the identifier, ...?

This is not so, at least not in the context of this question. Prior to the C ++ standard version, until 2014, the bare double semicolon did not qualify as a qualifier for nested names. The 2003 version of the standard indicated that the naming specifier took one of two forms in the BNF:

  • class-or-namespace-name :: nested-name-specifier opt
  • class-or-namespace-name :: template nested-name-specifier

There was no room for naked class ::CC in this specification. Version 2011 added a few bits to BNF for the nested qualifier name:

  • :: opt type_name ::
  • :: opt namespace-name ::
  • decltype-specifier ::
  • Sub-name identifier identifier ::
  • nested-name-specifier template opt simple-template-id ::

This still left no room for class ::CC . The 2014 version of the standard finally addressed this, indicating that the sub-name specifier is one of

  • ::
  • type-name ::
  • namespace-name ::
  • decltype-specifier ::
  • Sub-name identifier identifier ::
  • nested-name-specifier template opt simple-template-id ::


There are several ways to look at this interesting β€œfeature”. Firstly, this is a long-standing mistake in the language specification, first identified in 2002 as problem No. 355 . One of the tasks of the compiler provider is to identify and correct errors in the language specification, and then correct these errors in the upcoming version of the standard. From this point of view, template<> class ::CC<int> {...} should compile.

An alternative point of view is that it was not a mistake. The BNF for the nested qualifier in the 2003 and 2011 versions was completely clear, and therefore template<> class ::CC<int> {...} should not be compiled. Whether this was an unfortunate mistake or a deliberate feature did not matter. The code in the question should not be compiled from the point of view of this point of view.

Which point of view is true is controversial. The fact that the problem that first reported this discrepancy was not rejected was a sign that there was little meat in this report. On the other hand, nothing was done about this through two revisions of the standard, it also says something.

However, now that the standard has been clarified, there is an error in new versions of GCC, because even if you specify --std=c++14 , they do not allow compiling template<> class ::CC<int> {...} .

+3
source share

In a C ++ project, the nested name specifier is mentioned in [class] .11 :

If the head-class name contains a nested name specifier, the class specifier must refer to a class that was previously declared directly in the class or namespace to which the nested name specifier belongs, or to an element of the built-in namespace ([namespace.def]) of this space names (i.e., it is not simply inherited or entered using the declaration declaration), but the class specifier should appear in the namespace containing the previous declaration. In such cases, the qualifier of the nested class-head-name of the definition must not begin with the decltype specifier.

And it could also be :: according to [expr.prim.id.qual] .

In your code, you use class ::CC<int> in the template class specialization, for which [temp.expl.spec] .2 also applies:

Explicit specialization is declared in the namespace spanning the custom pattern. An explicit specialization whose declarator identifier or class name is not qualified is declared in the nearest spanning namespace of the template or, if the namespace is inline ([namespace.def]), any namespace from its spanning namespace is set, Such an expression can also be by definition. If the declaration is not a definition, specialization may be defined later ([namespace.memdef]).

Therefore, I think the use of a qualified name should be in order.

+2
source share

All Articles