Topic: const_cast


Author: jpotter@falcon.lhup.edu (John E. Potter)
Date: 1996/02/26
Raw View
The following produced interesting results on several compilers.  I am not
using the compilers to interpret the DWP, but am trying to use the DWP to
justify the compilers and predict the future.  None of these compilers
support the four new specific casts; however, I will try to explain their
actions in terms of them.  The question involves the first item following
return in fun.  I believe the += disambiguates to an expression statement.

struct I1 {
 I1 (int v) : x(v) { }
 I1& operator+= (const I1& rhs) { x += rhs.x; return *this; }
 int x;
 };
struct I2 {
 I2 (int v) : x(v) { }
 I2 (const I2& src) : x(src.x) { }
 I2& operator+= (const I2& rhs) { x += rhs.x; return *this; }
 int x;
 };
int nofun (const int& s) { return (int&)(s) += 10; }
int fun (const int& s) { return int(s) += 10; }
I1 fun (const I1& s) { I1 t(10); return I1(s) += t; }
I2 fun (const I2& s) { I2 t(10); return I2(s) += t; }

    comp1            comp2            comp3            comp4
nofun     const_cast<int&> const_cast<int&> const_cast<int&> const_cast<int&>

fun(int)  const_cast<int&> static_cast<int> static_cast<int> static_cast<int>
          *****            error lvalue     error lvalue     error lvalue
fun(I1)   static_cast<I1>  const_cast<I1&>  static_cast<I1>  static_cast<I1>
          no error         *****            no error         error lvalue
fun(I2)   static_cast<I2>  static_cast<I2>  static_cast<I2>  static_cast<I2>
    no error         no error         no error         no error

When I originally wrote fun, my intent was to create an unnamed temp and
return a modification of it.  This requires the use of a copy constructor
and I was surprised to find that I got different results when I wrote it
and when I let the compiler implicitly provide it.  fun(I2) gave me what
I wanted and has been permitted by many compilers.  If I read the DWP
correctly, constructors return rvalues and it is now illegal.  That's
fine with me.  In the future, if a compiler accepts fun(I2) it will not
be certified.  Or did I miss some other interpretation which would allow
fun(I2)?

Assuming that fun(I2) is not legal as a static_cast, is there any way to
justify the two compilers which interpreted similar expressions as
const_cast?  If so, a DWP compliant compiler would also be allowed
(required?) to use const_cast in fun(I2).  I usually assume that a
compiler will do what I tell it with references; whenever I could do it
with pointers.  All of the compilers above worked as expected with
nofun(int).  None of them would allow what the two seem to be doing.
Changing to pointers, I tried *&(I1)*s and was told that I could not
use & with an rvalue.  They also rejected (I1)*s.  Good.  I do not assume
that a compiler will only do with references what I could do with pointers.
Does the compiler have enough freedom to place its implicit dereference of
the lvalue (bad words, hear the thought) into the cast to produce a valid
const_cast?  I hope not.

I also tried to turn fun(I1) into the same results as fun(I2) by placing
an explicit use of the copy constructor prior to the cast.  Now the
compiler must implicitly generate it.  That did not change anything.
Does the DWP require the compiler to "remember" that it implicitly
generated something?  Does an explicitly written copy constructor with
the same semantics as the implicit one have different meaning?

Thanks,
John
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ:    http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/28
Raw View
jpotter@falcon.lhup.edu (John E. Potter) writes:

>The following produced interesting results on several compilers.  I am not
>using the compilers to interpret the DWP, but am trying to use the DWP to
>justify the compilers and predict the future.  None of these compilers
>support the four new specific casts; however, I will try to explain their
>actions in terms of them.  The question involves the first item following
>return in fun.  I believe the += disambiguates to an expression statement.
>
>struct I1 {
> I1 (int v) : x(v) { }
> I1& operator+= (const I1& rhs) { x += rhs.x; return *this; }
> int x;
> };
>struct I2 {
> I2 (int v) : x(v) { }
> I2 (const I2& src) : x(src.x) { }
> I2& operator+= (const I2& rhs) { x += rhs.x; return *this; }
> int x;
> };
>int nofun (const int& s) { return (int&)(s) += 10; }
>int fun (const int& s) { return int(s) += 10; }
>I1 fun (const I1& s) { I1 t(10); return I1(s) += t; }
>I2 fun (const I2& s) { I2 t(10); return I2(s) += t; }
>
>    comp1            comp2            comp3            comp4
>nofun     const_cast<int&> const_cast<int&> const_cast<int&> const_cast<int&>

The compilers are all correct here.

>fun(int)  const_cast<int&> static_cast<int> static_cast<int> static_cast<int>
>          *****            error lvalue     error lvalue     error lvalue

Compiler `comp1' is wrong.  The other compilers are correct.
The invocation of `+=' is illegal here, because 5.17[expr.ass]/1
requires that the left-hand operand be an lvalue, and `int(s)' is not
an lvalue.

>fun(I1)   static_cast<I1>  const_cast<I1&>  static_cast<I1>  static_cast<I1>
>          no error         *****            no error         error lvalue

Compiler `comp2' is wrong.  The other compilers are correct.

5.17[expr.ass]/1 does not apply in this case, because `+=' here
refers to an overloaded operator, not the built-in version.
In this case, `+=' is a member function, and it is OK for the
left-hand operand to be a non-lvalue.

Some people might argue that 12.2[class.temporary] allows the behaviour
of `comp2', but if that is true, it is a problem in the wording of 12.2 -
I think the intent is definitely that `I1(s)' should be required to make
a copy of `s'.

>fun(I2)   static_cast<I2>  static_cast<I2>  static_cast<I2>  static_cast<I2>
>    no error         no error         no error         no error

Again, no problems here -- all the compilers are correct.

>When I originally wrote fun, my intent was to create an unnamed temp and
>return a modification of it.  This requires the use of a copy constructor
>and I was surprised to find that I got different results when I wrote it
>and when I let the compiler implicitly provide it.

As I said above, I think this is a bug in `comp2'.

>fun(I2) gave me what
>I wanted and has been permitted by many compilers.  If I read the DWP
>correctly, constructors return rvalues and it is now illegal.

You don't read it correctly.  Constructors return rvalues, but a call
to a member function does not require an lvalue, even if that member
function is `operator +='.

>Does an explicitly written copy constructor with
>the same semantics as the implicit one have different meaning?

No.

--
Any mail to me between Feb 24th and 27th may have gone to the bit bucket
(#&$^@$!# mail software silently ignored disk full error).  Please resend.
(comp.std.c++ articles were not affected, so no need to resend those.)
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]