标准提供以下注释:
[注意:不可能使用指向成员的指针 可变成员修改const类对象。例如,
struct S { S() : i(0) { } mutable int i; }; void f() { const S cs; int S::* pm = &S::i; // pm refers to mutable member S::i cs.*pm = 88; // ill-formed: cs is a const object }
-end note]
但是我们可以使用object-expression来修改具有mutale数据成员的const对象。
#include <iostream>
struct A
{
A(){ }
mutable int a;
};
const A a;
int main()
{
a.a = 4;
std::cout << a.a; //4
}
但ISO / IEC Derictive告诉
文件正文中的注释和示例只能是 用于提供旨在协助的其他信息 理解或使用该文件。它们不得含有 要求(“应”;见3.3.1和表H.1)或任何信息 被认为是使用该文件必不可少的[...]
这意味着我在Q开头提供的注释不是必需的。
我正在寻找一个规范性要求,明确排除了这种使用。
答案 0 :(得分:1)
在该说明之前,您将找到以下内容:
对cv-quali fi cation的限制,以及操作数的cv-qualivors结合起来产生结果的cv-qualiv的方式,与5.2.5中给出的E1.E2的规则相同< / p>
跳到5.2.5,你会发现:
如果E2是非静态数据成员且E1的类型是“cq1 vq1 X”,并且E2的类型是“cq2 vq2 T”,则表达式指定由第一个表达式指定的对象的指定成员。如果E1是左值,则E1.E2是左值;否则E1.E2是一个x值。让符号vq12代表vq1和vq2的“联合”;也就是说,如果vq1或vq2是易失性的,则vq12是易失性的。同样,让符号cq12代表cq1和cq2的“联合”;也就是说,如果cq1或cq2是const,则cq12是const。如果E2被声明为可变成员,那么E1.E2的类型是“vq12 T”。如果E2未被声明为可变成员,则E1.E2的类型为“cq12 vq12 T”。
cs.*pm
中const限定符的并集是const
,mutable
成员的例外不适用于指针。
如果您认为存储类说明符不属于该类型,那么更容易理解,那么编译器如何能够区分成员的mutable
和非mutable
指针?
struct S;
void f(const S& s, int S::* pm)
{
s.*pm = 1; // How do I know if pm points to a mutable member? S isn't even defined!
}
简单地说,没有指向mutable
成员的指针,就像没有指向static
成员的指针一样,指向类型的存储类是未知的(该类型只能由const
和/或volatile
)限定。