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)
根据哥伦布的评论,
\n\n\n\n\n当然,嵌套名称说明符可以是::,CC是标识符,\xe2\x80\xa6?
\n
事实并非如此,至少在这个问题的背景下并非如此。直到 2014 版 C++ 标准为止,裸露的双分号还没有资格作为嵌套名称说明符。该标准的 2003 版本表示,嵌套名称说明符采用 BNF 中的两种形式之一:
\n\n:: 嵌套名称说明符opt :: template 嵌套名称说明符没有足够的空间容纳裸露的设备class ::CC以符合此规格。2011 版本为 BNF 添加了相当多的嵌套名称说明符:
templateopt simple-template-id ::这还是没有留下余地class ::CC。该标准的 2014 版本最终解决了这个问题,指出嵌套名称说明符是以下之一:
::::::::::template选择 简单模板 ID ::
\n有多种方法可以了解这个有趣的“功能”。一是这是语言规范中长期存在的错误,于 2002 年首次被识别为问题 #355。编译器供应商的工作之一是识别和修补语言规范中的错误,然后在即将发布的标准中修复这些错误。从这一点来看,template<> class ::CC<int> {...}应该可以编译。
另一种观点是这不是一个错误。2003 和 2011 版本标准中嵌套名称说明符的 BNF都非常清晰,因此template<> class ::CC<int> {...}不应编译。这是一个不幸的错误功能还是故意的功能并不重要。从这个角度来看,问题中的代码不应该编译。
哪种观点正确,值得商榷。最先报告这种差异的问题没有被拒绝,这表明该报告有一些内容。另一方面,标准的两次修订没有采取任何措施也说明了一些问题。
\n\n也就是说,现在标准已经明确,新版本的 GCC 中存在一个错误,因为即使指定了--std=c++14,它们也不允许template<> class ::CC<int> {...}编译。