我正在试图弄清楚是否要提交针对Clang,GCC或两者的错误报告(我已经针对Clang主干和GCC 4.7.2进行了测试:如果有人可以针对GCC主干进行验证,那将会有所帮助) :
基本上,在默认和C ++ 11模式下,以下代码三行文件与-fsyntax-only
编译良好:
class A {
friend void f();
};
请注意,之前没有声明f()
,但这显然是正确的。
但是,Clang(但不是GCC)拒绝接受以下内容:
class A {
friend void ::f();
};
来自Clang的错误是“在指定的范围内找不到类型为'void()'的函数名为'f'”,但我在标准中找不到任何理由来处理这种情况与前一种不同,所以我认为这是一个错误;我可能错了(我正在阅读N3242,但是,AFAIK是C ++ 11之前的最后一次公开选秀)。
然而,下一个例子被GCC拒绝而不是Clang:
void f() { }
void g()
{
class A {
friend void ::f();
};
}
来自GCC的错误是“没有事先声明的本地类中的朋友声明'void f()'”,这似乎没有意义,因为void ::f()
应引用f()
中的friend
全局命名空间,已声明。 (不要紧,void g()
{
class A {
friend void ::f();
};
}
- 来自本地班级的全局职能是荒谬的,它似乎并非违法......)
最后,最后一个例子被Clang和GCC拒绝:
{{1}}
错误是本地类中的“友元声明'void f()',而没有事先声明”和“在指定的范围”中没有找到名为'f'的类型为'void()'的函数。现在,从11.4p11开始,似乎有一些理由拒绝在本地类中拒绝朋友声明先前未声明的函数,但该段实际上是:
如果朋友声明出现在本地班级(9.8)且指定的名称是非限定名称,则先行 查询声明时不考虑最内层封闭非类范围之外的范围。 对于朋友函数声明,如果没有事先声明,则该程序格式错误......
本声明的非法性显然是基于本段的第二句,但我不清楚该句是否应适用于具有合格名称的情况,如本案所用。 (可以说,无论是否使用“非限定名称”,整个段落都适用于“本地类”,并且“和指定的名称是非限定名称”条款仅适用于所描述的查找在第一句话中,但它似乎是一个延伸...我想象这是一种可能性的唯一原因是因为两个编译器都拒绝它。)
无论如何,从我所知道的情况来看,所有这四个案件(无论他们是否合理)都应该是合法的;即使不是,Clang和GCC中至少有一个在第二和第三种情况下是错误的。任何人都可以在我的逻辑中发现错误吗?
第三和第四个案件无疑是荒谬的;但我可以看到第二个案例打破某人的有效和有用的代码,所以我有点惊讶它从来没有被捕获过,如果它确实是一个错误。
答案 0 :(得分:4)
我认为8.3 / 1中的这句话是相关的:
当 declarator-id 被限定时,声明应引用先前声明的限定符所引用的类或命名空间的成员(或者,如果是命名空间,则引用元素)该命名空间的内联命名空间集(7.3.1))或其特化;该成员不应仅仅由声明者的嵌套名称说明符指定的类或命名空间中的 using-declaration 引入 - ID
该段正在讨论任何类型的声明中的声明者。所以我认为例2和4是不正确的,clang是正确的,而gcc是错误的。
(如果全局声明是一个模板函数,示例3可能会变得更加真实。对于全局函数模板或来自本地类的特殊化来说可能是有用的。如果允许的话,那么您编写的示例3可能也是如此为了保持一致是合法的。)