Pregunta

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?

¿Fue útil?

Solución

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)

Otros consejos

With regard to your allSame template, you can also use allSatisfy from std.typetuple:

import std.typetuple;

/** Returns: true if all types T are the same. */
template allSame(T...) {

    template isType(X) { enum bool isType = is(X == T[0]); }
    enum bool allSame = allSatisfy!(isType, T);
}

void main()
{
    static assert(!allSame!(int, float, string));
    static assert(allSame!(int, int, int));
    static assert(allSame!(int));
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top