"Mutable base class": Operator to base class "will never be used"


I have a question regarding operators to base classes, or rather, how
clang sees them. I stumbled upon the situation where I wanted a base
class to be basically "mutable" (in my case a Mutex class). One can
argue about the uglyness in such a solution, but I cannot get over the
fact that this doesn't compile, and what surprises me is the warning
clang gives me.

Consider the following, a simple class A with an int and a function,
and an empty class B inheriting A:

class A {
  A() : i(17) {}
  void f() {}
  int i;
class B : public A {
  B() {}
  operator A&() const { return (A&)*const_cast<B*>(this); } // warning:
conversion function converting 'B' to its base class 'A' will never be
  operator int&() const { return const_cast<B*>(this)->i; } // However
this is fine

int main(int argc, char** argv) {
  B b;
  const B& cb = b;
  int& i(cb); // This is a valid implicit cast
  A& a(cb); // error: binding of reference to type 'A' to a value of
type 'B const' drops qualifiers

Is there some part of the language saying that an operator to a
reference of a class which happens to be a base class, is not valid
(or rather valid but "not used")? I'm not sure, so I don't want to
file a bug report, but rather let you analyze it first.

I can (almost) understand that C++ wants to own the right to casts
from B& to A& or at least use the default cast (static cast I
suppose), but in this case, I want to implicitly cast from "const B&"
to "A&" for which there is no default cast, using my operator. What
exactly is it I don't get?
I understand the error because of the warning, but I don't understand
the warning, or rather *why* I get the warning. A description of why
the "conversion function" will never be used, would be suitable, in
clang's output.

This is clang 2.8 from 64-bit vanilla Ubuntu 10.10.


No, but the derived-to-base conversion takes precedence over user-defined conversions. The warning exists because a user-defined conversion from derived to base will never be used under normal circumstances, but the derived-to-base conversion will make code that appears to use it compile, which might not be what the programmer expects.

In your special case, though, I think Clang is wrong. There is no derived-to-base conversion that adds drops const, and const Derived isn't reference-compatible with non-const Base either, so those code paths shouldn't be taken.


You can't use an explicit conversion operator to convert between reference-related types.

C++0x [dcl.init.ref]p5:
  A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
    If the reference is an lvalue reference and the initializer expression
      — is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or
      — has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an lvalue of type “cv3 T3,” where “cv1 T1” is reference-compatible with “cv3 T3”
      [then bind the reference to the lvalue / operator result]
    Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference and the initializer expression shall be an rvalue or have a function type. [followed by lots of cases and a description of how to do this]

Note in particular the condition on the clause permitting conversion operators (i.e. the second bullet). This was a clarification in '0x.