digitalmars.D.learn - Problem with casting instance reference to void* and back.
- Vlad Leberstein (41/41) Jul 27 2015 Hi! My use case requires interaction with C API which in turn
- anonymous (26/67) Jul 27 2015 In the first example, you pass a pointer to a class instance. You
- anonymous (12/15) Jul 27 2015 actually i meant you pass an untyped pointer, so when you cast as
- Artur Skawina via Digitalmars-d-learn (7/32) Jul 27 2015 auto self = cast(TestInterface)cast(Object) rawSelf
- Vlad Leberstein (1/2) Jul 27 2015 Works like a charm! Thank you both!
Hi! My use case requires interaction with C API which in turn implies storing object instance reference as void *. I'm using gdc 4.9.2 and everything worked fine with "object -> void * -> object" conversion, but "object -> void * -> interface" failed. The stripped-down example is something like this: interface TestInterface { void testMethod(); } class TestImpl : TestInterface { void testMethod() { writefln("TestImpl::testMethod\n"); } }; void testDispathcer(void *rawSelf) { auto self = cast(TestInterface) rawSelf; // nothing happens self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(cast(void *) t); return 0; } However this works: void testDispathcer(TestImpl rawSelf) { auto self = cast(TestInterface) rawSelf; // TestImpl::testMethod is printed to stdout self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(t); return 0; } Is there any way to handle such situation without resorting to templating dispatcher with every *Impl type? As second example works as expected I presume that runtime loses some type information to perform downcast and maybe it's possible to extract it and store externally and merge back later? I'm quite new to D and sorry if the question is dumb. Any help would be greatly appreciated! Thanks in advance!
Jul 27 2015
On Monday, 27 July 2015 at 12:03:06 UTC, Vlad Leberstein wrote:Hi! My use case requires interaction with C API which in turn implies storing object instance reference as void *. I'm using gdc 4.9.2 and everything worked fine with "object -> void * -> object" conversion, but "object -> void * -> interface" failed. The stripped-down example is something like this: interface TestInterface { void testMethod(); } class TestImpl : TestInterface { void testMethod() { writefln("TestImpl::testMethod\n"); } }; void testDispathcer(void *rawSelf) { auto self = cast(TestInterface) rawSelf; // nothing happens self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(cast(void *) t); return 0; } However this works: void testDispathcer(TestImpl rawSelf) { auto self = cast(TestInterface) rawSelf; // TestImpl::testMethod is printed to stdout self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(t); return 0; } Is there any way to handle such situation without resorting to templating dispatcher with every *Impl type? As second example works as expected I presume that runtime loses some type information to perform downcast and maybe it's possible to extract it and store externally and merge back later? I'm quite new to D and sorry if the question is dumb. Any help would be greatly appreciated! Thanks in advance!In the first example, you pass a pointer to a class instance. You cannot get the vtbl entry for the interface like this. Instead try to do this in 2 steps: --- import std.stdio; interface TestInterface { void testMethod(); } class TestImpl : TestInterface { void testMethod() { writefln("TestImpl::testMethod\n"); } }; void testDispathcer(void *rawSelf) { auto obj = cast(Object) rawSelf; auto self = cast(TestInterface) obj; // nothing happens self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(cast(void *) t); return 0; } ---
Jul 27 2015
On Monday, 27 July 2015 at 13:11:33 UTC, anonymous wrote:In the first example, you pass a pointer to a class instance. You cannot get the vtbl entry for the interface like this. Instead try to do this in 2 steps:actually i meant you pass an untyped pointer, so when you cast as interface it's not like if the vtbl of an object is queried. So you have to upcast to an Object then cast to the interface, which is not a simple cast (it get something in the virtual table. void testDispathcer(void *rawSelf) { auto obj = cast(Object) rawSelf; // reinterpret auto self = cast(TestInterface) obj; // get vtbl entry , it's not a simple cast // works self.testMethod(); }
Jul 27 2015
On 07/27/15 14:03, Vlad Leberstein via Digitalmars-d-learn wrote:Hi! My use case requires interaction with C API which in turn implies storing object instance reference as void *. I'm using gdc 4.9.2 and everything worked fine with "object -> void * -> object" conversion, but "object -> void * -> interface" failed. The stripped-down example is something like this: interface TestInterface { void testMethod(); } class TestImpl : TestInterface { void testMethod() { writefln("TestImpl::testMethod\n"); } }; void testDispathcer(void *rawSelf) { auto self = cast(TestInterface) rawSelf; // nothing happens self.testMethod(); } int main(string[] args) { auto t = new TestImpl(); testDispathcer(cast(void *) t); return 0; }Is there any way to handle such situation without resorting to templating dispatcher with every *Impl type?auto self = cast(TestInterface)cast(Object) rawSelf [you should probably check for null, and consider using a reinterpret-cast (`testDispathcer(*cast(void **)&t)`) because a "normal" one can be overridden by the class, sometimes accidentally] artur
Jul 27 2015
auto self = cast(TestInterface)cast(Object) rawSelfWorks like a charm! Thank you both!
Jul 27 2015