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

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Gustaf Räntilä
Hi,

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 {
public:
        A() : i(17) {}
        void f() {}
        int i;
};
class B : public A {
public:
        B() {}
        operator A&() const { return (A&)*const_cast<B*>(this); } // warning:
conversion function converting 'B' to its base class 'A' will never be
used
        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
        a.f();
}

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.

Gustaf
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

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

Sebastian Redl

On 21.12.2010, at 14:45, Gustaf Räntilä wrote:

> 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")?

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.

Sebastian


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

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

John McCall

On Dec 21, 2010, at 9:44 AM, Sebastian Redl wrote:

>
> On 21.12.2010, at 14:45, Gustaf Räntilä wrote:
>
>> 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")?
>
> 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.

John.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev