Thread overview
cast ref pointer
Jan 18, 2018
Luís Marques
Jan 18, 2018
Adam D. Ruppe
Jan 18, 2018
Luís Marques
Jan 18, 2018
ag0aep6g
Jan 18, 2018
Luís Marques
Jan 18, 2018
Luís Marques
Jan 18, 2018
Adam D. Ruppe
January 18, 2018
This works, obviously (i.e. it prints 42):

    void foo(ref int* a)
    {
        static int j = 42;
        a = &j;
    }

    void bar(int* ptr)
    {
        foo(ptr);
        writeln(*ptr);
    }

    void main()
    {
        int i = 7;
        bar(&i);
    }

Unfortunately, if bar for some reason receives a void* pointer (e.g. C callback) this doesn't work:

    void bar(void* ptr)
    {
        foo(cast(int*) ptr); // error
        writeln(*cast(int*) *ptr);
    }

I think the underlying idea is sound (use ptr as an lvalue, but with int* type), but since you can't cast(ref int*), I don't know how to express it in D code.
January 18, 2018
On Thursday, 18 January 2018 at 15:25:38 UTC, Luís Marques wrote:
> I think the underlying idea is sound (use ptr as an lvalue, but with int* type), but since you can't cast(ref int*), I don't know how to express it in D code.

Simply define an intermediate.

int* tmp = cast(int*) that_void_pointer;
foo(tmp);
January 18, 2018
On 01/18/2018 04:25 PM, Luís Marques wrote:
> This works, obviously (i.e. it prints 42):
> 
>      void foo(ref int* a)
>      {
>          static int j = 42;
>          a = &j;
>      }
> 
>      void bar(int* ptr)
>      {
>          foo(ptr);
>          writeln(*ptr);
>      }
> 
>      void main()
>      {
>          int i = 7;
>          bar(&i);
>      }
> 
> Unfortunately, if bar for some reason receives a void* pointer (e.g. C callback) this doesn't work:
> 
>      void bar(void* ptr)
>      {
>          foo(cast(int*) ptr); // error

You need a reinterpret-style cast here to get an lvalue:

    foo(* cast(int**) &ptr);

The result has the same type (int*), but it refers to the very same memory location as `&ptr` does. So it's not just a temporary value, and it can be passed in a `ref` parameter.

>          writeln(*cast(int*) *ptr);

You're dereferencing twice here. Do it only once, after casting:

    writeln(* cast(int*) ptr);

>      }
Alernatively, you can make a local variable for the casted pointer and use that instead of the `ptr`:

    int* casted_ptr = cast(int*) ptr;
    foo(casted_ptr);
    writeln(*casted_ptr);

That way, `ptr` itself won't be updated by `foo`, of course. But `ptr` isn't a `ref` parameter, so this only affects the insides of `bar` anyway.
January 18, 2018
On 1/18/18 10:25 AM, Luís Marques wrote:
> This works, obviously (i.e. it prints 42):
> 
>      void foo(ref int* a)
>      {
>          static int j = 42;
>          a = &j;
>      }
> 
>      void bar(int* ptr)
>      {
>          foo(ptr);
>          writeln(*ptr);
>      }

Note, this, to me, seems odd. Of course this is not the full case, but you are not affecting anything except for the value of the local `ptr`. So I would be concerned this may not be what you want (if you are looking to affect something outside the callback).

Other than that, the other responders are right, you just need to reinterpret the pointer.

-Steve
January 18, 2018
On Thursday, 18 January 2018 at 16:08:32 UTC, Adam D. Ruppe wrote:
> Simply define an intermediate.
>
> int* tmp = cast(int*) that_void_pointer;
> foo(tmp);

In my actual case bar also receives its pointer by ref, so you would have to do something like:

int* tmp = cast(int*) that_void_pointer;
foo(tmp);
that_void_pointer = tmp;

This is a bit more noisy than what I would prefers (a more care is needed to check if this is properly optimized away), that's why I was looking for a more direct route, like a cast.
January 18, 2018
On Thursday, 18 January 2018 at 16:20:35 UTC, Steven Schveighoffer wrote:
> Note, this, to me, seems odd. Of course this is not the full case, but you are not affecting anything except for the value of the local `ptr`. So I would be concerned this may not be what you want (if you are looking to affect something outside the callback).

Yeah, I went overboard in reducing my scenario :( The actual function bar also receives by ref its pointer.
January 18, 2018
On Thursday, 18 January 2018 at 16:14:18 UTC, ag0aep6g wrote:
> On 01/18/2018 04:25 PM, Luís Marques wrote:
> You need a reinterpret-style cast here to get an lvalue:
>
>     foo(* cast(int**) &ptr);

Right, that's what I wanted. Ugh, for some reason I was totally confused about this :-)

>>          writeln(*cast(int*) *ptr);
>
> You're dereferencing twice here. Do it only once, after casting:

That was just a typo.

> That way, `ptr` itself won't be updated by `foo`, of course. But `ptr` isn't a `ref` parameter, so this only affects the insides of `bar` anyway.

Yeah, it was a bad example.
January 18, 2018
On Thursday, 18 January 2018 at 16:26:54 UTC, Luís Marques wrote:
> The actual function bar also receives by ref its pointer.

you might be better off receiving a pointer-to-pointer instead of ref. Then it will be encoded in the type and thus you can cast outer layers too and use intermediate more easily if you need.

void foo(void** f) {
   bar(cast(int**) f);
}

int* a;
foo(&a);