通过指向成员的指针突变可变数据成员

时间:2014-09-28 08:14:32

标签: c++ language-lawyer mutable

标准提供以下注释:

  

[注意:不可能使用指向成员的指针   可变成员修改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
}

DEMO

但ISO / IEC Derictive告诉

  

文件正文中的注释和示例只能是   用于提供旨在协助的其他信息   理解或使用该文件。它们不得含有   要求(“应”;见3.3.1和表H.1)或任何信息   被认为是使用该文件必不可少的[...]

这意味着我在Q开头提供的注释不是必需的。

我正在寻找一个规范性要求,明确排除了这种使用。

1 个答案:

答案 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限定符的并集是constmutable成员的例外不适用于指针。

如果您认为存储类说明符不属于该类型,那么更容易理解,那么编译器如何能够区分成员的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)限定。