A couple of times I've run into the situation where a "new" C++ class is written to exactly match "legacy" C structures. At the edges where old code meets new code, you can cast one to the other in-place. For example, given a huge mess of data that includes
oldstruct s1;
you could write the line
newclass& s2= reinterpret_cast
AMDG On 12/13/2010 3:52 PM, John Dlugosz wrote:
A couple of times I've run into the situation where a "new" C++ class is written to exactly match "legacy" C structures. At the edges where old code meets new code, you can cast one to the other in-place. For example, given a huge mess of data that includes oldstruct s1; you could write the line newclass& s2= reinterpret_cast
(s1); because s2 is designed to exactly overlay s1. It might even derive from it, and just add member functions and friendlier accessors. Another example I've seen is a class that contains nothing but a char* pointer member, that contains overloaded operators to replace the ancient str* functions. In particular, it has an operator==, so casting an array of char* to an array of that class allowed std::find to be used! I don't like the wild and unchecked use of reinterpret_cast, but I can see the point for these and think the idiom can be tamed. Basically, I want to write a cisam_cast that behaves like a reinterpret_cast but only for those conversions I've explicitly nominated as being cisam's. CISAM is "compatible in structure and meaning", and I avoid calling it "upgrade" because it works in either direction or sideways between different code bases' definitions of the same wire data.
I'm thinking that I should be able to declare something like template<> cisam
: std::tr1::true_type {}; to enable cisam_cast<xxx>(a_yyy) to have the same meaning as reinterpret_cast (a_yyy), etc. (foreshadowing hard question...) Since it would be common to make a new class to wrap a primitive type or old struct, a shortcut would be to include a typedef yyy cisam; as a member of xxx.
Now I get around to my actual question: the "etc." part above. Given that xxx and yyy are cisam-mates, I want to enable not only xxx to yyy and vice versa, but handle const and volatile qualified forms with correct cv-modifier carry-through, and handle pointers to them to any depth, which is complicated by the fact that there could be cv-qualifiers at any level.
In the earlier example, the original code was something like: char* A[7]; char* val; //... Str* SA= reinterpret_cast
((char**)A); and I would want Str* SA= cisam_cast (A); to be accepted. Note that the cisam-ness is between (char*) and (Str), so there are a different number of stars on the before and the after. So, how might I write the cisam_cast machinery to elaborate the basic cisam definitions into the full set of allowed casts?
something like this?
template
something like this?
template
struct cisam : cisam {}; template struct cisam : cisam {}; template struct cisam : cisam {}; template struct cisam : cisam {};
Yes. But I was worried that it's not really that simple. ===== Begin Stupid Footer ===== TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
At Mon, 13 Dec 2010 18:52:34 -0500, John Dlugosz wrote:
[1
] [1.1 ] A couple of times I've run into the situation where a "new" C++ class is written to exactly match "legacy" C structures. At the edges where old code meets new code, you can cast one to the other in-place. For example, given a huge mess of data that includes oldstruct s1; you could write the line newclass& s2= reinterpret_cast (s1); because s2 is designed to exactly overlay s1.
Unless oldstruct and newclass are both POD, the above has
implementation-defined behavior. The portable way to do it, if they
indeed have the same layout, is
newclass& s2= *static_cast
2010/12/14 Dave Abrahams
Unless oldstruct and newclass are both POD, the above has implementation-defined behavior. The portable way to do it, if they indeed have the same layout, is
newclass& s2= *static_cast
(static_cast (&s1));
Using s2 causes undefined behavior (accessing an object through a pointer to unrelated type). reinterpret_cast has the same problem and compilers taking advantage of anti-aliasing rules can produce "unexpected" results for this code. Roman Perepelitsa.
At Tue, 14 Dec 2010 09:07:30 +0100, Roman Perepelitsa wrote:
[1
] [1.1 ] 2010/12/14 Dave Abrahams Unless oldstruct and newclass are both POD, the above has implementation-defined behavior. The portable way to do it, if they indeed have the same layout, is
newclass& s2= *static_cast
(static_cast (&s1)); Using s2 causes undefined behavior (accessing an object through a pointer to unrelated type).
No, not if the types are layout-compatible. Look it up (it will cost you a thorough reading ;->).
reinterpret_cast has the same problem
reinterpret_cast causes implementation-defined, not undefined, behavior IIRC, in the cases where the static_cast approach works. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
On 14.12.2010 01:29, Dave Abrahams wrote:
At Mon, 13 Dec 2010 18:52:34 -0500, John Dlugosz wrote:
[1
] [1.1 ] A couple of times I've run into the situation where a "new" C++ class is written to exactly match "legacy" C structures. At the edges where old code meets new code, you can cast one to the other in-place. For example, given a huge mess of data that includes oldstruct s1; you could write the line newclass& s2= reinterpret_cast (s1); because s2 is designed to exactly overlay s1. Unless oldstruct and newclass are both POD, the above has implementation-defined behavior. The portable way to do it, if they indeed have the same layout, is newclass& s2= *static_cast
(static_cast (&s1)); 5.2.10p7 in the current draft defines the semantics of reinterpret_cast between standard-layout types via this double static_cast, so there is no difference.
Sebastian
At Tue, 14 Dec 2010 10:44:12 +0100, Sebastian Redl wrote:
On 14.12.2010 01:29, Dave Abrahams wrote:
At Mon, 13 Dec 2010 18:52:34 -0500, John Dlugosz wrote:
[1
] [1.1 ] A couple of times I've run into the situation where a "new" C++ class is written to exactly match "legacy" C structures. At the edges where old code meets new code, you can cast one to the other in-place. For example, given a huge mess of data that includes oldstruct s1; you could write the line newclass& s2= reinterpret_cast (s1); because s2 is designed to exactly overlay s1. Unless oldstruct and newclass are both POD, the above has implementation-defined behavior. The portable way to do it, if they indeed have the same layout, is newclass& s2= *static_cast
(static_cast (&s1)); 5.2.10p7 in the current draft defines the semantics of reinterpret_cast between standard-layout types via this double static_cast, so there is no difference.
That's an draft for C++0x. I assume the OP wants the code to work under C++03. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
On 14.12.2010 11:17, Dave Abrahams wrote:
At Tue, 14 Dec 2010 10:44:12 +0100, Sebastian Redl wrote:
5.2.10p7 in the current draft defines the semantics of reinterpret_cast between standard-layout types via this double static_cast, so there is no difference. That's an draft for C++0x. I assume the OP wants the code to work under C++03.
I'd be very surprised if you could show me a compiler that differs in this behavior. I'd be even more surprised if any compiler would now change behavior *away* from what is coming for C++0x. Sebastian
I'd be very surprised if you could show me a compiler that differs in this behavior. I'd be even more surprised if any compiler would now change behavior *away* from what is coming for C++0x.
Sebastian
I agree. Except for some exotic architectures, and looking only at the "sensible" case where the two types have the same alignment and are probably just declaring the same data members in the same order, the reinterpret_cast should give the same address. FWIW, the code base in question is currently compiled under Microsoft VS2008, and will soon move to VS2010. And contains reinterpret_cast calls. I'm replacing them with something tamer, as well as making sure subsequent use of the idiom is more formalized. Defining a cisam explicitly indicates something that needs to be tested. Having random casts throughout the code is always a wildcard. ===== Begin Overly-Verbose Footer ===== TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
At Tue, 14 Dec 2010 12:21:49 +0100, Sebastian Redl wrote:
On 14.12.2010 11:17, Dave Abrahams wrote:
At Tue, 14 Dec 2010 10:44:12 +0100, Sebastian Redl wrote:
5.2.10p7 in the current draft defines the semantics of reinterpret_cast between standard-layout types via this double static_cast, so there is no difference. That's an draft for C++0x. I assume the OP wants the code to work under C++03.
I'd be very surprised if you could show me a compiler that differs in this behavior. I'd be even more surprised if any compiler would now change behavior *away* from what is coming for C++0x.
That may not be the only thing that matters. Perhaps he has program analysis tools like a lint that would detect the issue. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (5)
-
Dave Abrahams
-
John Dlugosz
-
Roman Perepelitsa
-
Sebastian Redl
-
Steven Watanabe