Passing Templated Function Arguments Solely by Reference

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Jul 9 00:43:56 PDT 2014


On 07/08/2014 05:13 PM, "Nordlöw" wrote:

 > If I want randInPlace to take value arguments (such as structs) by
 > reference and reference types (classes) as normal is this

I don't understand what it means to fill a struct or a class object with 
random content.

 > /** Generate Random Contents in $(D x).
 >   */
 > auto ref randInPlace(T)(auto ref T x) @safe /* nothrow */ if 
(isIterable!T)

hasAssignableElements is more correct.

 > {
 >      foreach (ref elt; x)
 >      {
 >          import std.range: ElementType;
 >          static if (isInputRange!(ElementType!T))

The documentation of hasAssignableElements mentions that it implies 
isForwardRange and it makes sense: You don't want the range to be 
consumed as an InputRange would do.

 >              elt[].randInPlace;
 >          else
 >              elt.randInPlace;
 >      }
 >      return x;
 > }

 > And how does this compare to using x[].randInPlace() when x is a static
 > array?

Range algorithms don't work with static arrays because they can't 
popFront(). The solution is to use a slice to the entire array as you've 
already done as x[]. ;)

 > Does x[] create unnecessary GC-heap activity in this case?

No. Static array will remain in memory and x[] will be a local slice. A 
slice consists of two members, the equivalent of the following:

struct __SliceImpl
{
     size_t length;
     void * pointer_to_first_element;
}

 > I'm wondering because (auto ref T x) is just used in two places in
 > std.algorithm and std.range in Phobos. Is this a relatively new
 > enhancement?

Phobos algorithms use ranges. The following is what I've come up with 
very quickly:

import std.stdio;
import std.range;
import std.traits;
import std.random;

void randInPlace(R)(R range)
     if (hasAssignableElements!R)
{
     foreach (ref e; range) {
         e.randInPlace();
     }
}

void randInPlace(E)(ref E element)
     if (isNumeric!E)
{
     // BUG: Never assigns the value E.max
     element = uniform(E.min, E.max);
}

void randInPlace(E)(ref E element)
     if (isBoolean!E)
{
     element = cast(bool)uniform(0, 2);
}

void main()
{
     auto arr = [ [ 0, 1, 2 ], [ 3, 4, 5 ] ];
     arr.randInPlace();
     writefln("%s", arr);

     auto barr = [ [ false, true ], [ false, true ] ];
     barr.randInPlace();
     writefln("%s", barr);
}

Ali



More information about the Digitalmars-d-learn mailing list