www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - casting to structure

reply Igor Shirkalin <mathsoft inbox.ru> writes:
Hello!

I'm in trouble with opCast function.
Is it possible to cast some (integral) type to user defined 
structure?

We have a structure:

struct A
{
   void * data; // void * type is just for example
   // no matter what is here
}

How can we define opCast operator to make the following 
expression working properly?

auto a = cast(A) 12;

The task arised from core.sys.windows module. This module defines 
a lot of windows specific types based on HANDLE: these are HWND, 
HDC, HBITMAP, etc. The problem is that all these types are 
identical, and it is too bad. When I redefine these types like:
        alias Typedef!(void*) HDC;

I have another problem:

   HWND_MESSAGE = cast(HWND) -3;  // Error: cannot cast expression 
-3 of type int to Typedef!(void*, null, null)

So, is there any solution to this?
Jun 24
next sibling parent reply Igor Shirkalin <mathsoft inbox.ru> writes:
On Saturday, 24 June 2017 at 20:43:48 UTC, Igor Shirkalin wrote:
 struct A
 {
   void * data; // void * type is just for example
   // no matter what is here
 }
I know that if I add constructor this(int) struct A { void * p; this(int k) { p = cast(void*)k; } } auto a = cast(A) 23; // it works Is it possible without such a constructor?
Jun 24
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 24 June 2017 at 21:11:13 UTC, Igor Shirkalin wrote:
 Is it possible without such a constructor?
No. Also, the above works because of the following [1]:
 Casting a value v to a struct S, when value is not a struct of 
 the same type, is equivalent to: `S(v)`
[1] https://dlang.org/spec/expression.html#CastExpression
Jun 24
prev sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 24 June 2017 at 20:43:48 UTC, Igor Shirkalin wrote:
 I'm in trouble with opCast function.
 Is it possible to cast some (integral) type to user defined 
 structure?
Hi, unfortunately not: - Operator overloading is supported via member functions only [1]. - Corollary: You cannot overload operators for builtin types (i.e. where the cast gets rewritten to `e.opOverloaded` where `e` is a builtin type) - opCast needs to be defined for the type that you are casting from [2], not the one you are casting to => You cannot overload opCast for casting from builtin types
 [...]

 How can we define opCast operator to make the following 
 expression working properly?

 auto a = cast(A) 12;
You cannot. As any such cast operation would have to create a new A object, anyway (and would as such be a wrapper around a (possibly default) constructor), I suggest using elaborate constructors: --- struct A { void* data; this(int data) { this.data = cast(void*) data; } } ... auto a = A(12); ---
 The task arised from core.sys.windows module. This module 
 defines a lot of windows specific types based on HANDLE: these 
 are HWND, HDC, HBITMAP, etc. The problem is that all these 
 types are identical, and it is too bad.
Why is this a problem? That *is* how the Windows C API works AFAIK. Typesafety would require a higher abstraction level than the Windows C API functions provide, anyway.
 When I redefine these types like:
        alias Typedef!(void*) HDC;

 I have another problem:

   HWND_MESSAGE = cast(HWND) -3;  // Error: cannot cast 
 expression -3 of type int to Typedef!(void*, null, null)
You have explicitly asked for those two types to be different from each other [3]; that means they are also *not* implicitly convertible to each other and thus you also cannot cast from one to the other without defining an opCast (which you can't in this case, since the source type is a builtin type).
 So, is there any solution to this?
Define a struct for HWND as shown above for A and use constructors. Add an `alias this` to the wrapped pointer value. Word of warning, though: What you're doing is highly unsafe. [1] https://dlang.org/spec/operatoroverloading.html [2] https://dlang.org/spec/operatoroverloading.html#cast [3] https://dlang.org/phobos/std_typecons.html#.Typedef
Jun 24
parent Igor Shirkalin <mathsoft inbox.ru> writes:
On Saturday, 24 June 2017 at 21:41:22 UTC, Moritz Maxeiner wrote:
 Hi, unfortunately not:
 - Operator overloading is supported via member functions only 
 [1].
 - Corollary: You cannot overload operators for builtin types 
 (i.e. where the cast gets rewritten to `e.opOverloaded` where 
 `e` is a builtin type)
 - opCast needs to be defined for the type that you are casting 
 from [2], not the one you are casting to
 => You cannot overload opCast for casting from builtin types
 [...]
 You cannot. As any such cast operation would have to create a 
 new A object, anyway (and would as such be a wrapper around a 
 (possibly default) constructor), I suggest using elaborate 
 constructors:
Thank you for your detailed explanation!
 Word of warning, though: What you're doing is highly unsafe.
I guess it is unsafe, but core.sys.windows module works this way.
 That *is* how the Windows C API works AFAIK.
I have no choice except for using it as it is.
 Define a struct for HWND as shown above for A and use 
 constructors. Add an `alias this` to the wrapped pointer value.
That was the first thing I did. And it is led me to my question. Thank you!
Jun 24