Шаблонная функция Variadic с аргументами одного типа

Как ограничить шаблонную функцию с переменным числом аргументов, чтобы все ее аргументы были одного типа?

Мне нужно это для специализации

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 .. $]);
}

который может пересылать l-значения, используя auto ref в качестве возвращаемого типа. Что-то по пути

auto ref either(T...

это должно удовлетворить

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

Это позволяет передавать значения через логические схемы either и every (не показаны), аналогичные and() и or() в Лиспе.

Это позволит еще более эффективно использовать функциональные конструкции в D для тех, кто предпочитает его.

Обновить

Я считаю, что нашел рабочее решение:

/** 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;

Однако тело двух версий either идентично. Это кажется ненужным. Является ли миксин лучшим способом устранить эту избыточность?


person Nordlöw    schedule 07.09.2013    source источник


Ответы (2)


Вам нужно написать шаблон, который определяет, все ли типы в кортеже типов одинаковы:

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 && allSame!T)
person Peter Alexander    schedule 07.09.2013
comment
Я тоже был удивлен. У Phobos довольно много функций для кортежей типов, но нет этой. - person Peter Alexander; 07.09.2013
comment
Мое решение работает в большинстве случаев. Однако, если мы хотим, чтобы он также пересылал ссылки const и immutable, я считаю, что должен как-то изменить второй пример. Но я не знаю, как указать вариативный аргумент ref T a как inout. Любые идеи? - person Nordlöw; 12.09.2013

Что касается вашего шаблона allSame, вы также можете использовать allSatisfy из 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));
}
person Andrej Mitrović    schedule 07.09.2013
comment
Также мог бы сделать (NoDuplicates!T).length == 1, хотя это не так самодокументировано :) - person Peter Alexander; 07.09.2013
comment
Это мило! еще 3 символа (не заставляйте меня начинать с правил SO..) - person Andrej Mitrović; 07.09.2013