UFCS functions with both pointers and refs

Dave P. dave287091 at gmail.com
Tue Dec 15 20:38:04 UTC 2020


On Tuesday, 15 December 2020 at 19:45:50 UTC, Q. Schroll wrote:
> On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote:
>> On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote:
>>> On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote:
>>>> Do I have to write both and have one forward to the other 
>>>> for more
>>>> complicated functions?
>>>
>>> For free functions, yes.
>>
>> Is there any way to write the function as a template that is 
>> generic over a parameter being a pointer or a reference, but 
>> does not allow passing a copy?
>
> I'm not sure what you mean by a reference. D doesn't have 
> references in general, only class references that are just 
> glorified pointers. There are also `ref` parameters, but those 
> aren't generally referred to as "references" and are inside the 
> function almost indiscernible from non-ref parameters. So, I'll 
> ignore that.
>
> Copying only takes place under one circumstance: When an lvalue 
> is passed to a function that does not take that argument by 
> `ref`. So one possibility is to just define that overload and 
> @disable it. You don't even need a template for this:
>
>     void f(    X x); // matches lvalues and rvalues
>     void f(ref X x); // matches lvalues only
>
> The latter is a better match than the former for lvalues. 
> @disable'ing it will do the job. On the other hand, not 
> @disable'ing it will make `f` work with any argument by moving 
> rvalues to the former overload and referencing lvalues using 
> the second one.
>
> On templates, those can be unified by slapping `auto ref` 
> before the parameter. You can also use `auto ref` (which infers 
> `ref` from the passed argument) and check it with an `if` 
> template constraint:
>
>     void f(T)(auto ref T arg)
>         if (!__tratis(isRef, arg)) // only accepts non-ref args
>     { /* your code here */ }
>
> The constraint can easily be flipped.

The use case would be to define extension methods on a struct 
outside of where the struct is defined. The extension method 
mutates the state of the struct, so I want to ensure I am 
modifying the original struct and not a copy. If it’s a method 
and I call it on a pointer to the struct, the pointer will get 
auto-dereferenced and everything is great. So my question is that 
if I want an extension method as a free function, do I have to 
write both the version whose first argument is a pointer to the 
struct and the version whose first argument is a ref, or is there 
some keyword or other technique so that the pointer gets 
auto-dereferenced the same way as if it were a method. It sounds 
like the answer is no and I have to write a version that just 
dereferences the pointer and calls the ref version.

Thanks for the explanation though!


More information about the Digitalmars-d-learn mailing list