15

我正在尝试确定是否针对 Clang、GCC 或两者提交错误报告(我已经针对 Clang 主干和 GCC 4.7.2 进行了测试:如果有人可以针对 GCC 主干验证这一点会有所帮助):

基本上,以下代码三行文件-fsyntax-only在默认和 C++11 模式下可以正常编译:

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- 从本地类中调用全局函数是荒谬的,它似乎并不违法......)

最后,最后一个示例被 Clang 和 GCC 拒绝:

void g()
{
    class A {
        friend void ::f();
    };
}

错误分别是“在本地类中没有事先声明的朋友声明'void f()'”和“在指定范围内找不到名为'f'且类型为'void ()'的函数”。现在,从 11.4p11 开始,似乎有一些理由拒绝本地类中先前未声明的函数的朋友声明,但该段实际上是:

如果友元声明出现在本地类 (9.8)中并且指定的名称是非限定名称,则在不考虑最内层非类范围之外的范围的情况下查找先前的声明。对于友元函数声明,如果没有事先声明,则程序是非良构...

该声明的非法性显然是基于本段中的第二句话,但我不清楚该句子是否也应适用于限定名称的情况,正如在本案中使用的那样。(可以说,无论是否使用“非限定名称”,整个段落都可能适用于“本地类”情况,并且“并且指定的名称是非限定名称”子句仅适用于所描述的查找在第一句话中,但这似乎有点牵强……我认为这是一种可能性的唯一原因是因为两个编译器都拒绝它。)

无论如何,据我所知,所有这四个案例(无论它们是否合理)都应该是合法的;即使不是,在第二种和第三种情况下,Clang 和 GCC 中至少有一个是错误的。谁能在我的逻辑中找到错误?

第三种和第四种情况无疑是荒谬的。但我可以看到第二种情况破坏了某人的有效和有用的代码,所以我有点惊讶它从未被抓住,如果它确实是一个错误。

4

1 回答 1

4

我认为 8.3/1 中的这句话是相关的:

declarator-id被限定时,声明应引用限定符所指的类或命名空间的先前声明的成员(或者,在命名空间的情况下,该命名空间的内联命名空间集合的元素(7.3 .1)) 或其专业化;该成员不应仅由声明符id的嵌套名称说明符指定的类或命名空间范围内的using 声明引入。

该段在任何类型的声明中都在谈论一般的声明符。所以我认为示例 2 和 4 格式不正确,clang 是正确的,而 gcc 是错误的。

(如果全局声明是模板函数,示例 3 可能会变得更加现实。将全局函数模板或本地类的特化作为朋友可能会很有用。如果允许,您编写的示例 3 也可能是合法的一致性。)

于 2013-03-15T05:25:59.533 回答