Search code examples
dtemplate-specializationvariadic-functionslvalue

Variadic Templated Function with Arguments all of Same Type


How do I restrict a variadic templated function to forcing its arguments to all be of the same type?

I need this for a specialization of

CommonType!T either(T...)(T a) if (a.length >= 1)
{
    static if (T.length == 1)
        return a[0];
    else
        return a[0] ? a[0] : either(a[1 .. $]);
}

that can forward l-values using auto ref as return type. Something along the way

auto ref either(T...

that should satisfy

unittest {
    int x = 1, y = 2;
    either(x, y) = 3;
    assert(x == 3);
}

This allows values to be forwarded through the logicals either and every (not shown) similar to Lisps's and() and or().

This would enable even more powerful use of functional constructs in D for those who prefer it.

Update

I believe I've found a working solution as:

/** Returns: true if all types T are the same. */
template allSame(T...) {
    static if (T.length <= 1) {
        enum bool allSame = true;
    } else {
        enum bool allSame = is(T[0] == T[1]) && allSame!(T[1..$]);
    }
}

CommonType!T either(T...)(T a) if (a.length >= 1) {
    static if (T.length == 1) {
        return a[0];
    } else {
        return a[0] ? a[0] : either(a[1 .. $]);
    }
}
auto ref either(T...)(ref T a) if (a.length >= 1 && allSame!T) {
    static if (T.length == 1) {
        return a[0];
    } else {
        return a[0] ? a[0] : either(a[1 .. $]);
    }
}

alias either or;

However, the body of the two versions of either are identical. This seems unneccessary. Is a mixin the best way to remove this redundancy?


Solution

  • You'll need to write a template that determines if all types in a type tuple are the same:

    template allSame(T...)
    {
        static if (T.length <= 1)
            enum bool allSame = true;
        else
            enum bool allSame = is(T[0] == T[1]) && allSame!(T[1..$]);
    } 
    

    Then just use this as a template constraint:

    CommonType!T either(T...)(T a) if (a.length >= 1 && allSame!T)