clang issue with 'mutable' ?

Hello,

I have just run into an issue with some C++ code that I could reduce to
this case:

  template <typename T>
  struct wrapper
  {
    wrapper() : member() {}
    mutable T member;
  };

  int main()
  {
    wrapper<int const> w;
  }

clang would raise the error "'mutable' and 'const' cannot be mixed",
while the same compiles (and works !) fine with g++.

(Please note that the above may not look very meaningful, but in the
original case I extracted this from it definitely does :slight_smile: )

Could someone please confirm that this is a clang bug, or otherwise
explain if it is indeed illegal C++ ?

Many thanks,
    Stefan

Interestingly GCC ToT (g+±tot (GCC) 4.9.0 20130829 (experimental)) rejects this the same way Clang does, but 4.8.1 does not (it accepts it).

Interesting. Unfortunately I still don't entirely understand why the
code is rejected. Is there any wording in the C++ spec that suggests
that the "wrapper" template may not be instantiated with some const type
? In my reading, a "mutable" member is simply a statement about it not
being part of the "logically const" state of the containing object,
which is entirely orthogonal to the question of whether the member
itself is immutable. Obviously combining "const" and "mutable" in a
single declaration is meaningless. But as in my code, both qualifiers
can still end up in the same spot through parametrization, which seems
entirely reasonable to me. Am I wrong ?

While I can think of some workarounds, I'd rather understand what the
issue is before making any attempt at working around it.

Many thanks,
        Stefan

Clang is right; gcc is wrong. [dcl.stc] of the standard says, “The mutable specifier … cannot be applied to names declared const or static, and cannot be applied to reference members.”

I tried looking into the standard (n3485) and in 7.1.1 [dcl.stc] I got:

10/ The mutable specifier can be applied only to names of class data members (9.2) and cannot be applied to names declared const or static, and cannot be applied to reference members. [Example:

class X {
mutable const int* p; // OK
mutable int* const q; // ill-formed
};

– end example]

As you mentioned, though, this applies to “names declared const”, and it is not clear whether it should cover parameterised types. Specifically I am confused by:

5.2.5 [expr.ref]

4/ If E2 is declared to have type “reference to T,” then E1.E2 is an lvalue; the type of E1.E2 it T. Otherwise, one of the following rules applies.

[…]

  • If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; otherwise, it is a prvalue. Let the notation vq12 stand ofor the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for union cq1 and cq2, that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.

[…]

Of interest, contrast: the type of E2 is “cq2 vq2 T” versus If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T” and note that no special note is made (there) than E2 should not evaluate to “const” something.

Interesting tidbit.

– Matthieu

Hello,

  template <typename T>
  struct wrapper
  {
    wrapper() : member() {}
    mutable T member;
  };

  int main()
  {
    wrapper<int const> w;
  }

clang would raise the error "'mutable' and 'const' cannot be mixed",
while the same compiles (and works !) fine with g++.

(Please note that the above may not look very meaningful, but in the
original case I extracted this from it definitely does :slight_smile: )

Could someone please confirm that this is a clang bug, or otherwise
explain if it is indeed illegal C++ ?

C++11 §7.1.1p10 says:

The mutable specifier can be applied only to names of class data members (9.2) and cannot be
applied to names declared const or static, and cannot be applied to reference members.

With the example of:

class X {
  mutable const int* p; // OK
  mutable int* const q; // ill-formed
};

So I'd say both clang and gcc ToT are correct to reject it.

HTH,
Jonathan