Topic: Clarification of 5.2.3 [expr.type.conv]


Author: ademkin@earthlink.net (Andrew Demkin)
Date: Tue, 23 Apr 2002 12:53:34 GMT
Raw View
This message is a follow-up to a question I posted a couple of months back (see "Safety of functional-style casts", 19 Dec, 2001). In that thread, Martin von Loewis kindly provided one (apparently common) interpretation of some confusing language in the standard. I'm again seeking some clarification.

Section 5.2.3 [expr.type.conv] says of a "functional-style" explicit type conversion:

   If the expression list is a single expression, the type conversion
   expression is equivalent (in definedness, and if defined in meaning)
   to the corresponding cast expression (5.4).

Given the above, and the following defintions,

   struct A {};
   struct B {};

   typedef A* a_ptr;
   typedef B* b_ptr;

   a_ptr a;

should the interpretation of

   b_ptr b(a);

be equivalent to

1) 'b_ptr b = static_cast<b_ptr>(a)', or
2) 'b_ptr b = reinterpret_cast<b_ptr>(a)' ?


This question relates to my original post of Dec. 19. On this topic, I think there may be more than one defect report worth submitting to the committee, but I'm trying to pinpoint the section(s) against which I should file.

Thanks,
Andrew.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ron Natalie <ron@sensor.com>
Date: Wed, 24 Apr 2002 00:45:43 GMT
Raw View

Andrew Demkin wrote:

>
> should the interpretation of
>
>    b_ptr b(a);
>
> be equivalent to
>

The answer is that 5.2.3 doesn't apply at all to the expresion you wrote.
It's not a functional cast at all, but direct initialization.  It's
ill-formed, there's no defined conversion from a_ptr to b_ptr.

Now perhaps you meant something like:

 b_ptr b = bptr(a);

which via 5.2.3 means that it is the same as:
 b_ptr b = (bptr) a;

which goes to the rules for the type conersion rules in 5.4.

- const_cast (doesn't apply, not changing just const/volatile)
- static_cast (nope, no defined conversion from b_ptr to a_ptr or
 vice_versa)
- static_cast followed by const_cast (nope).
- reinterpret_cast (bingo, this one works!)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Wed, 24 Apr 2002 00:46:04 GMT
Raw View
Andrew Demkin wrote:
>
> This message is a follow-up to a question I posted a couple of months back (see "Safety of functional-style casts", 19 Dec, 2001). In that thread, Martin von Loewis kindly provided one (apparently common) interpretation of some confusing language in the standard. I'm again seeking some clarification.
> Section 5.2.3 [expr.type.conv] says of a "functional-style" explicit type conversion:
>
>    If the expression list is a single expression, the type conversion
>    expression is equivalent (in definedness, and if defined in meaning)
>    to the corresponding cast expression (5.4).
>
> Given the above, and the following defintions,
>
>    struct A {};
>    struct B {};
>
>    typedef A* a_ptr;
>    typedef B* b_ptr;
>
>    a_ptr a;
>
> should the interpretation of
>
>    b_ptr b(a);
>
> be equivalent to
>
> 1) 'b_ptr b = static_cast<b_ptr>(a)', or
> 2) 'b_ptr b = reinterpret_cast<b_ptr>(a)' ?
>
> This question relates to my original post of Dec. 19. On this topic, I think there may be more than one defect report worth submitting to the committee, but I'm trying to pinpoint the section(s) against which I should file.

The declaration

 b_ptr b(a);

does not involve a function-style explicit conversion. Section 5.2.3 is
therefore irrelevant. It's parsed in accordance with 8.5p1, and is
therefore a direct initialization, with "a" as the initializing
expression-list. This form is described in 8.5p12. The applicable rules
are given in the last bullet of 8.5p14 (none of the earlier bullets
apply). It calls for 'a' to be converted to type b_ptr, using the
Standard Conversions defined in clause 4. None of those conversions
allow a pointer to a structure to be converted to a pointer to an
unrelated structure. Per 8.5p14: "if the conversion cannot be done, the
initialization is ill-formed".

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Andrew Demkin <ademkin@earthlink.net>
Date: Wed, 24 Apr 2002 13:30:06 GMT
Raw View
Hi Ron,

That'll teach me for posting right before bed.
As you guessed, I intended to write:

b_ptr b = bptr(a);

Thanks for confirming that this is intended to map to reinterpret_cast. I
find the wording in 5.4 paragraph 5 ("if a conversion can be
interpreted...") to be confusing since it doesn't indicate whether
well-formedness is a consideration or not. This is one part of the standard
which I think could be better written, but perhaps it's technically not a
defect.

If you don't mind, here's a follow-up question...

Is there a documented rationale for why a functional style conversion should
consider reinterpret_cast at all? The current semantics seem to introduce a
hole in the type system that doesn't seem useful, particularly when there
are also explicit cast expressions and cast operators which can be used for
the same purpose.

For additional context, please refer to my previous message ("Safety of
functional-style casts") regarding the lack of safety in bind1st() and
bind2nd(). I realize that the bind1st problem can be fixed by replacing the
functional style conversion with a static_cast expression, and I plan to now
file a defect for it, but doing so seems an ugly workaround for what should
be better default type-safety.

Any comments?

Thanks very much,
Andrew.


Ron Natalie wrote:

> The answer is that 5.2.3 doesn't apply at all to the expresion you wrote.
> It's not a functional cast at all, but direct initialization.  It's
> ill-formed, there's no defined conversion from a_ptr to b_ptr.
>
> Now perhaps you meant something like:
>
>         b_ptr b = bptr(a);
>
> which via 5.2.3 means that it is the same as:
>         b_ptr b = (bptr) a;
>
> which goes to the rules for the type conersion rules in 5.4.
>
> - const_cast (doesn't apply, not changing just const/volatile)
> - static_cast (nope, no defined conversion from b_ptr to a_ptr or
>         vice_versa)
> - static_cast followed by const_cast (nope).
> - reinterpret_cast (bingo, this one works!)


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ron Natalie <ron@sensor.com>
Date: Wed, 24 Apr 2002 16:21:35 GMT
Raw View

Andrew Demkin wrote:
>
> Is there a documented rationale for why a functional style conversion should
> consider reinterpret_cast at all? The current semantics seem to introduce a
> hole in the type system that doesn't seem useful, particularly when there
> are also explicit cast expressions and cast operators which can be used for
> the same purpose.

The decision was made to make a single operand functional conversion
be the same as the explicit type conversion operator.  I can't vouch
for why, I personally find it CONFUSING to have the thing behave one
way with any number of operators other than one and to have it behave
a different way with exactly 1.

Once you get past that, the explicit type conversion, commonly called
C-style cast, has to work the way it does.  The cast in C was sort of
loopy.  It originally was documented to behave pretty much like static_cast
works in C++ (essentially it said that cast was the same as assigning
to an invented temporary variable).  It was then added that it would
do the sledge-hammer conversion that reinterpret cast would do (to
convert integers to pointers etc...).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Wed, 24 Apr 2002 17:58:02 GMT
Raw View
"Ron Natalie" <ron@sensor.com> wrote in message
news:3CC6CA62.7284B926@sensor.com...
[cast operator]
> originally was documented to behave pretty much like static_cast
> works in C++ (essentially it said that cast was the same as assigning
> to an invented temporary variable).

But static_cast in C++ can also cast int to enum, void *
to non-void * and so on.  Maybe there ought to be a special
cast that really is just limited to the assignment conversions.

I guess you can template one for simple types as

  template<typename T> T assign_cast(T x) { return x; }


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Andrew Demkin <ademkin@earthlink.net>
Date: Thu, 25 Apr 2002 16:54:54 GMT
Raw View
Ron Natalie wrote:

> Andrew Demkin wrote:
> >
> > Is there a documented rationale for why a functional style conversion should
> > consider reinterpret_cast at all? The current semantics seem to introduce a
> > hole in the type system that doesn't seem useful, particularly when there
> > are also explicit cast expressions and cast operators which can be used for
> > the same purpose.
>
> The decision was made to make a single operand functional conversion
> be the same as the explicit type conversion operator.  I can't vouch
> for why, I personally find it CONFUSING to have the thing behave one
> way with any number of operators other than one and to have it behave
> a different way with exactly 1.

Yes, the problem I see is that functional-style conversions of class types
currently have different type checking guarantees than functional
style-conversions of pointer types. This is unfortunate, particularly for generic
template programming, because it can easily lead to the problem exhibited by
bind1st()/bind2nd().

One solution is to require more liberal use of static_cast in templates that
convert values and *could be* parameterized on non-class types, but this seems
both messy and prone to error.

Another solution is to require that functional-style conversions (not cast
expressions) honor the same type checking rules outlined in 5.2.9
[expr.static.cast] and 4.10 [conv.ptr], etc.

Andrew.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]