以下代码符合C ++标准吗?
struct B
{
protected:
struct Type {};
};
struct D : B, B::Type
{};
int main()
{
D d;
return 0;
}
我在https://stripe.com/docs/api#create_source-owner-address上尝试过。 MSVC(VS 2017 RTW)接受它。 gcc(7.3)和clang(6.0.0)拒绝它。
答案 0 :(得分:12)
代码符合标准,自C ++ 11以来,但不在C ++ 03中。
C ++ 11到C ++ 17在[class.access]部分的介绍中说明了这一点,成员访问控制:
子句[class.access]中的所有访问控制都会影响从特定实体的声明访问类成员名称的能力,包括声明的实体名称前面的声明部分,如果实体是class,类的成员的定义出现在类的 member-specification 之外。
在相同的标准版本中,下面的示例非常类似于您的问题,但即使有点棘手:
[实施例:
class A { ... protected: struct B { }; }; ... struct D: A::B, A { };
...
A::B
作为基本说明符的使用格式正确,因为D
派生自A
,因此检查 base-specifiers ,直到看到整个 base-specifier-list 。 - 结束示例]
但是我看到你做的结果相同:g ++和clang ++都拒绝这些程序,无论我给出什么-std=
参数。这是一对编译器错误。
C ++ 03有这个而不是我上面引用的第一段:
子句[class.access]中的所有访问控制都会影响从特定范围访问类成员名称的能力。对于出现在成员类定义之外的类成员定义中使用的名称的访问控制,就像整个成员定义出现在成员类的范围内一样....
类定义的 base-specifier 不在该类的范围内,因此C ++ 03不允许使用受保护或私有名称作为派生类的基类名称否则可以访问该名称。
答案 1 :(得分:0)
如果D来自B,它可以访问受保护的成员,所以这应该是正确的。问题是,如果它在编译时已经已经访问,或者只有在类型完成后才能访问它。
请注意,如果你转动两个(将B放在逗号后面),它应该会失败。