Search code examples
constantsdrefrvalue

How to accept both ref and non ref values as a function argument


I want to take any kind of values inside a function (r/lvalue) and I also want to ensure that the value will not be mutated in the scope of the function, even if the value itself is not a const.

struct Tree(T) {
    T item;
    Tree!T* parent, left, right;

    this(T item) {
        this.item = item;
    }

    Tree!T* searchTree(const ref T item) {
        if (&this is null)
            return null;
        if (this.item == item)
            return &this;
        return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item);
    }
}

unittest {
    auto text1 = "Hello", text2 = "World";

    auto tree2 = Tree!string(text1);
    assert(tree2.searchTree(text2) is null);
    assert(tree2.searchTree(text1) !is null);

}

This works with ref parameters however if I give int literals to the function, it fails:

    auto tree1 = Tree!int(4);
    assert(tree1.searchTree(5) is null);
    assert(tree1.searchTree(4) !is null);

Solution

  • Templates to the rescue! D has a feature called auto ref that automatically generates the overloads for ref and non-ref parameters. The only requirement is that the function must be a template.

    For your searchTree function, that means it needs to have this signature:

        Tree!T* searchTree()(const auto ref T item)
    

    With that simple change, your code should compile and do The Right Thing™.