我试图理解为什么我们不能通过class-member-access表达式使用嵌套类型。 例如,我们有以下类:
struct U
{
struct A
{
static int v;
int a;
};
struct B
{
int b;
};
};
U a;
typedef a.A T; //'a' does not name a type
int main()
{
std::cout << typeid(a.A).hash_code(); //invalid use of 'struct U::A'
struct a.A b; //trying to declare a variable of type U::A
//error: expected unqualified-id before '.' token
a.A b; //the same as above
//error: expected unqualified-id before '.' token
a.A.v = 5; //error: expected unqualified-id before '.' token
}
标准说:
第N3797::5.2.5/2 [expr.ref]
部分
对于第一个选项(点),第一个表达式应该是完整的 班级类型。对于第二个选项(箭头),第一个表达式应为 有指向完整类类型的指针。表达式E1-> E2是 转换为等效形式(*(E1))。E2; 5.2.5的其余部分 将只解决第一个选项(点)。在任何一种情况下, id-expression应该命名该类或其基类之一的成员。
然而,N3797::9.2/1 [class.mem]
部分给出了类成员的定义:
类的成员是数据成员,成员函数(9.3),嵌套 类型和枚举器。
所以我无法看到嵌套类型的这种使用限制。为什么不呢?
答案 0 :(得分:5)
在[expr.ref]
中向下看(4.4)如果E2是嵌套类型,则表达式E1.E2是不正确的。
答案 1 :(得分:2)
标准是讨论变量所代表的对象的类型 您需要访问类的范围,而不是变量。
要从U
访问嵌套类的成员,您需要从该类型创建成员,有两种方法可以做到这一点:
struct U
{
struct A
{
static int v;
int a;
} VarNameForA;
struct B
{
int b;
};
B VarNameOfB;
};
使用范围运算符::
来访问类型。
以下是您尝试的所有内容:
U a;
typedef decltype(a) varType;
typedef varType::A nestedType;
int main()
{
std::cout << typeid(U::A).hash_code();
struct U::A b;
U u;
u.VarNameForA.a = 5;
u.VarNameOfB.b = 6;
U::A::c = 3;
}
对于使用运算符dot (.)
的成员,对于类型和静态,您需要使用scope ::
运算符。
答案 2 :(得分:2)
您尝试使用a.A
作为类型说明符。
您引用的类成员访问规则(5.2.5)仅对表达式有效,不适用于类型说明符和类型名称(5/1:“表达式是一系列运算符和指定计算的操作数。表达式可能会产生一个值,并可能导致副作用。“)。
您必须在标准的第7.1.6节中查看类型说明符的规则。在那里没有使用运算符.
。精心设计的类型(7.1.6.3)使用::
来组合类型名称上的组件。
clang 错误消息比您从编译器获得的错误消息更明确:“不能在类型上使用点运算符”)。
顺便说一句,你的U
是一个空结构(没有数据),只有嵌套类型的定义。这就是a.A.v = 5;
也是一个错误的原因:这里没有可以分配的左值。