为什么标准C++语法不能涵盖这种情况?

Jav*_*Man 7 c++ grammar language-lawyer c++11 c++03

我主要是指C++ 03标准,但是,在快速浏览之后,它也应该适用于C++ 11标准.

以下代码在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;
}
Run Code Online (Sandbox Code Playgroud)

请注意::CC<int>语法以引用全局命名空间中定义的模板.这NamespaceA::CC<int>::运算符前面的语法不同.使用其他一些工具,我试图使用C++ 03中的语法严格解析它,但它给了我错误,在我看来标准只接受NamespaceA::CC<int>类头声明中的表单.

仔细看看,问题在于class-head标准中的语法定义:

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)
Run Code Online (Sandbox Code Playgroud)

而且由于nested-name-specifier形式AA::bb::......,它不接受我的::CC.我的问题是,为什么C++标准不允许:: CC形式?这只是我对标准语法的错误解释吗?正确的语法应该是这样的:

class-head:
   ...
   class-key '::'(optional) nested-name-specifier(optional) template-id base-clause(optional)
Run Code Online (Sandbox Code Playgroud)

注意,上面的表单实际上是由其他地方的标准使用,例如,在指定declarator-id时:

declarator-id:
   id-expression
   ::(optional) nested-name-specifier(optional) class-name
Run Code Online (Sandbox Code Playgroud)

Dav*_*men 3

根据哥伦布的评论,

\n\n
\n

当然,嵌套名称说明符可以是::,CC是标识符,\xe2\x80\xa6?

\n
\n\n

事实并非如此,至少在这个问题的背景下并非如此。直到 2014 版 C++ 标准为止,裸露的双分号还没有资格作为嵌套名称说明符。该标准的 2003 版本表示,嵌套名称说明符采用 BNF 中的两种形式之一:

\n\n
    \n
  • 类或命名空间名称 :: 嵌套名称说明符opt
  • \n
  • 类或命名空间名称 :: template 嵌套名称说明符
  • \n
\n\n

没有足够的空间容纳裸露的设备class ::CC以符合此规格。2011 版本为 BNF 添加了相当多的嵌套名称说明符

\n\n
    \n
  • ::选择 类型名称::
  • \n
  • ::选择 命名空间名称::
  • \n
  • decl类型说明符::
  • \n
  • 嵌套名称说明 符标识符::
  • \n
  • 嵌套名称说明符 templateopt simple-template-id ::
  • \n
\n\n

这还是没有留下余地class ::CC。该标准的 2014 版本最终解决了这个问题,指出嵌套名称说明符是以下之一:

\n\n
    \n
  • ::
  • \n
  • 类型名称 ::
  • \n
  • 命名空间名称 ::
  • \n
  • decl类型说明符 ::
  • \n
  • 嵌套名称说明 符标识符 ::
  • \n
  • 嵌套名称说明符 template选择 简单模板 ID ::
  • \n
\n\n


\n有多种方法可以了解这个有趣的“功能”。一是这是语言规范中长期存在的错误,于 2002 年首次被识别为问题 #355。编译器供应商的工作之一是识别和修补语言规范中的错误,然后在即将发布的标准中修复这些错误。从这一点来看,template<> class ::CC<int> {...}应该可以编译。

\n\n

另一种观点是这不是一个错误。2003 和 2011 版本标准中嵌套名称说明符的 BNF都非常清晰,因此template<> class ::CC<int> {...}不应编译。这是一个不幸的错误功能还是故意的功能并不重要。从这个角度来看,问题中的代码不应该编译。

\n\n

哪种观点正确,值得商榷。最先报告这种差异的问题没有被拒绝,这表明该报告有一些内容。另一方面,标准的两次修订没有采取任何措施也说明了一些问题。

\n\n

也就是说,现在标准已经明确,新版本的 GCC 中存在一个错误,因为即使指定了--std=c++14,它们也不允许template<> class ::CC<int> {...}编译。

\n