也许我对[class.access]/7的理解不正确,但是

10

根据 [class.access]/7,我们有以下句子:

同样地,使用 A::B 作为 base-specifier 是合法的, 因为 D 是从 A 派生而来的,所以必须推迟检查 base-specifier, 直到整个 base-specifier-list 被看到。

class A {
protected:
    struct B { };
};
struct D: A::B, A { };

点击此处查看clang的实时示例。事实上,clang也对这个片段提出了抱怨,其中不需要推迟执行。

class A {
protected:
    struct B { };
};
struct D: A, A::B { };

为什么这段代码无法编译?

PS:gcc和VS21013也无法编译此代码。


对不起,我相信代码应该可以编译。 - Belloc
第二个片段做了什么? - 我猜是一些意想不到的事情。 - WorldSEnder
就[class.access]/7而言,这两个片段是等效的,也就是说,D是从A和A::B私有派生出来的。 - Belloc
首先,结构体B是受保护的,从它继承并在外部使用是有些错误的。 - user2946316
@nilo 但是[class.access]/7似乎表明,由于D派生自A,因此它可以访问A的受保护成员。 - Belloc
@nilo protected 的整个意义在于派生类 可以 看到该名称。如果您不希望该名称在定义类之外可见,则可以使用 private 关键字。 - user743382
2个回答

8
这只是编译器的一个错误。标准的规范文本支持该示例。多个编译器都有相同的错误,这意味着正确理解标准是棘手的。
有关此问题的GCC的clang的存在未解决的错误。请注意,一些相关情况实际上是C++03和C++11之间的微妙差别,但据我所知,不包括此问题。
[class.access]/1.2仅说明:
“protected”;即它的名称只能由声明它的类的成员和友元、从该类派生的类以及它们的友元使用(见11.4)。
而11.4没有进一步阐述。您正在使用类A的派生类D中的名称B。这没问题。

3

我认为这是clang的一个bug。Ideone也不接受这段代码:http://ideone.com/uiFl9L:

class A {
protected:
struct B { };
};
struct D: A::B, A { };

我查看了gcc-5.1.0、gcc-4.9和clang-3.7(rc2),标准明确规定此为正常代码(请参见问题),因此编译器存在问题。
示例澄清[class.access]/ 6的内容:
所有在第11条中的访问控制都会影响从特定实体的声明访问类成员名称的能力,包括在声明名称之前声明的实体的部分内容...
这意味着,根据[class.access] / 2的规定,一个类可以访问所有基类,即使它们尚未声明。

示例不是规范的,我的第一反应实际上是规范文本可能与示例相矛盾。但事实并非如此,但如果确实如此,编译器拒绝示例是正确的。 - user743382
@hvd,我添加了一个除了“它在示例中”之外的原因。 - WorldSEnder
这里不适用于“包括在声明实体名称之前的声明部分”。被声明的实体是D,类成员名称B出现在D之后。但你没有加粗的引用部分可能是一个很好的论据。 :) - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接