std.meta

Шаблоны для манипуляции списками аргументов шаблона (также известными, как списки типов).
Некоторые действия на последовательностях псевдонимов встроены в язык, как например, TL[n], который получает энный тип из последовательности псевдонимов. TL[lwr .. upr] возвращает новый список типов, который является срезом старого.
Несколько шаблонов в этом модуле используют или действуют в одноимённых шаблонах, которые принимают единственный аргумент и вычисляют логическую константу. Такие шаблоны называются шаблонными предикатами.
Category Templates
Строительные блоки Alias AliasSeq aliasSeqOf
Фильтрация последовательности псевдонимов Erase EraseAll Filter NoDuplicates
Иерархия типов в последовательности псевдонимов DerivedToFront MostDerived
Преобразование последовательности псевдонимов Repeat Replace ReplaceAll Reverse staticMap staticSort
Поиск в последовательности псевдонимов allSatisfy anySatisfy staticIndexOf
Операторы для логических шаблонных предикатов templateAnd templateNot templateOr
Создание экземпляра шаблона ApplyLeft ApplyRight

Ссылки: Основано на идеях в Таблице 3.1 из Modern C++ Design, Andrei Alexandrescu (Addison-Wesley Professional, 2001)

Лицензия:
Boost License 1.0.
Авторы:
Walter Bright, David Nadlinger

Исходный код: std/meta.d

template AliasSeq(TList...)
Создает последовательность из нуля или больше псевдонимов. Это чаще всего используется в качестве параметров шаблона или аргументов.
Примеры:
import std.meta;
alias TL = AliasSeq!(int, double);

int foo(TL td)  // тоже самое, что int foo(int, double);
{
    return td[0] + cast(int)td[1];
}
Примеры:
alias TL = AliasSeq!(int, double);

alias Types = AliasSeq!(TL, char);
static assert(is(Types == AliasSeq!(int, double, char)));
template Alias(alias a)

template Alias(T)
Позволяет создать псевдоним для любого единичного идентификатора, типа или выражения времени компиляции.
Не из всего можно непосредственно создавать псевдоним. Псевдоним нельзя объявить, например, из литерала:
alias a = 4; //Ошибка
С этим шаблоном, любую единичную сущность можно сделать псевдонимом:
alias b = Alias!4; //OK
Смотрите также:
Для создания сразу нескольких псевдонимов используйте AliasSeq
Примеры:
// Без Alias это приведет к сбою, если параметр Арг.[0], например, является значением,
// и понадобится некоторая логика для определения, когда использовать вместо этого enum
alias Head(Args ...) = Alias!(Args[0]);
alias Tail(Args ...) = Args[1 .. $];

alias Blah = AliasSeq!(3, int, "hello");
static assert(Head!Blah == 3);
static assert(is(Head!(Tail!Blah) == int));
static assert((Tail!Blah)[1] == "hello");
Примеры:
alias a = Alias!(123);
static assert(a == 123);

enum abc = 1;
alias b = Alias!(abc);
static assert(b == 1);

alias c = Alias!(3 + 4);
static assert(c == 7);

alias concat = (s0, s1) => s0 ~ s1;
alias d = Alias!(concat("Hello", " World!"));
static assert(d == "Hello World!");

alias e = Alias!(int);
static assert(is(e == int));

alias f = Alias!(AliasSeq!(int));
static assert(!is(typeof(f[0]))); //not an AliasSeq
static assert(is(f == int));

auto g = 6;
alias h = Alias!g;
++h;
assert(g == 7);
enum auto staticIndexOf(T, TList...);

enum auto staticIndexOf(alias T, TList...);
Возвращает индекс первого появления типа T в последовательности из нуля или больше типов TList. Если не обнаружено, возвращается -1.
Примеры:
import std.stdio;

void foo()
{
    writefln("The index of long is %s",
             staticIndexOf!(long, AliasSeq!(int, long, double)));
    // prints: The index of long is 1
}
template Erase(T, TList...)

template Erase(alias T, TList...)
Возвращает список типов, созданный из TList с удалением первого появления T, если присутствовал.
Примеры:
alias Types = AliasSeq!(int, long, double, char);
alias TL = Erase!(long, Types);
static assert(is(TL == AliasSeq!(int, double, char)));
template EraseAll(T, TList...)

template EraseAll(alias T, TList...)
Возвращает список типов, созданный из TList с удалением всех появлений T, если присутствовали.
Примеры:
alias Types = AliasSeq!(int, long, long, int);

alias TL = EraseAll!(long, Types);
static assert(is(TL == AliasSeq!(int, int)));
template NoDuplicates(TList...)
Возвращает список типов, созданный из TList с удалением всех дубликатов.
Примеры:
alias Types = AliasSeq!(int, long, long, int, float);

alias TL = NoDuplicates!(Types);
static assert(is(TL == AliasSeq!(int, long, float)));

// Bugzilla 14561: huge enums
alias LongList = Repeat!(1500, int);
static assert(NoDuplicates!LongList.length == 1);
template Replace(T, U, TList...)

template Replace(alias T, U, TList...)

template Replace(T, alias U, TList...)

template Replace(alias T, alias U, TList...)
Возвращает список типов, созданный из TList с заменой первого появления типа T на тип U, если обнаружено.
Примеры:
alias Types = AliasSeq!(int, long, long, int, float);

alias TL = Replace!(long, char, Types);
static assert(is(TL == AliasSeq!(int, char, long, int, float)));
template ReplaceAll(T, U, TList...)

template ReplaceAll(alias T, U, TList...)

template ReplaceAll(T, alias U, TList...)

template ReplaceAll(alias T, alias U, TList...)
Возвращает список типов, созданный из TList с заменой всех появлений типа T на тип U, если обнаружено.
Примеры:
alias Types = AliasSeq!(int, long, long, int, float);

alias TL = ReplaceAll!(long, char, Types);
static assert(is(TL == AliasSeq!(int, char, char, int, float)));
template Reverse(TList...)
Возвращает список типов, созданный из TList с противоположным порядком типов.
Примеры:
alias Types = AliasSeq!(int, long, long, int, float);

alias TL = Reverse!(Types);
static assert(is(TL == AliasSeq!(float, int, long, long, int)));
template MostDerived(T, TList...)
Возвращает тип из TList, который является наиболее производным от типа T. Если ни один не найден, возвращается Т.
Примеры:
class A { }
class B : A { }
class C : B { }
alias Types = AliasSeq!(A, C, B);

MostDerived!(Object, Types) x;  // x объявлен как тип C
static assert(is(typeof(x) == C));
template DerivedToFront(TList...)
Возвращает список типов TList с типами отсортированными так, чтобы наиболее производные типы находились сначала.
Примеры:
class A { }
class B : A { }
class C : B { }
alias Types = AliasSeq!(A, C, B);

alias TL = DerivedToFront!(Types);
static assert(is(TL == AliasSeq!(C, B, A)));
template staticMap(alias F, T...)
Вычисляет AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1])).
Примеры:
import std.traits : Unqual;
alias TL = staticMap!(Unqual, int, const int, immutable int);
static assert(is(TL == AliasSeq!(int, int, int)));
template allSatisfy(alias F, T...)
Независимо тестирует все переданные элементы на удовлетворение шаблонному предикату, то есть вычисляет F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).
Вычисление не обрывается, если встретился результат false; шаблонный предикат должен быть выполним со всеми данными элементами.
Примеры:
import std.traits : isIntegral;

static assert(!allSatisfy!(isIntegral, int, double));
static assert( allSatisfy!(isIntegral, int, long));
template anySatisfy(alias F, T...)
Независимо тестирует переданные элементы, удовлетворяет ли хотя бы один шаблонному предикату, то есть вычисляет F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1]).
Вычисление не обрывается, если встретился результат true; шаблонный предикат должен быть выполним со всеми данными элементами.
Примеры:
import std.traits : isIntegral;

static assert(!anySatisfy!(isIntegral, string, double));
static assert( anySatisfy!(isIntegral, int, double));
template Filter(alias pred, TList...)
Фильтрует AliasSeq, используя шаблонный предикат. Возвращает элементы AliasSeq, которые удовлетворяют предикату.
Примеры:
import std.traits : isNarrowString, isUnsigned;

alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int);
alias TL1 = Filter!(isNarrowString, Types1);
static assert(is(TL1 == AliasSeq!(string, wstring, char[])));

alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong);
alias TL2 = Filter!(isUnsigned, Types2);
static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong)));
template templateNot(alias pred)
Отрицает переданный шаблонный предикат.
Примеры:
import std.traits : isPointer;

alias isNoPointer = templateNot!isPointer;
static assert(!isNoPointer!(int*));
static assert(allSatisfy!(isNoPointer, string, char, float));
template templateAnd(Preds...)
Объединяет несколько шаблонных предикатов, используя логическую И, то есть создает новый предикат, который вычисляется в true для данного входа T тогда и только тогда, когда все переданные предикаты являются истиной для T.
Предикаты вычисляются слева направо, прерывая вычисление для ускорения,если встрелился ложный результат, в этом случае более поздние экземпляры не нужно компилировать.
Примеры:
import std.traits : isNumeric, isUnsigned;

alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned);
static assert(storesNegativeNumbers!int);
static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint);

// Пустой список предикатов всегда даёт true.
alias alwaysTrue = templateAnd!();
static assert(alwaysTrue!int);
template templateOr(Preds...)
Объединяет несколько шаблонных предикатов, используя логическую ИЛИ, то есть создает новый предикат, который вычисляется в true для данного входа T тогда, когда хотя бы один переданный предикат возвращает истину для T.
Предикаты вычисляются слева направо, прерывая вычисление для ускорения, если встрелился истинный результат, в этом случае более поздние экземпляры не нужно компилировать.
Примеры:
import std.traits : isPointer, isUnsigned;

alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned);
static assert( isPtrOrUnsigned!uint &&  isPtrOrUnsigned!(short*));
static assert(!isPtrOrUnsigned!int  && !isPtrOrUnsigned!(string));

// Пустой список предикатов всегда даёт true.
alias alwaysFalse = templateOr!();
static assert(!alwaysFalse!int);
template aliasSeqOf(alias range)
Преобразует входной диапазон range в последовательность псевдонимов.
Примеры:
import std.algorithm.iteration : map;
import std.algorithm.sorting : sort;
import std.string : capitalize;

struct S
{
    int a;
    int c;
    int b;
}

alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize());
static assert(capMembers[0] == "A");
static assert(capMembers[1] == "B");
static assert(capMembers[2] == "C");
Примеры:
static immutable REF = [0, 1, 2, 3];
foreach (I, V; aliasSeqOf!([0, 1, 2, 3]))
{
    static assert(V == I);
    static assert(V == REF[I]);
}
template ApplyLeft(alias Template, args...)

template ApplyRight(alias Template, args...)
Частично применяет Template, связывая его первые (left) или последние (right) аргументы с args.
Ведет себя подобно тождественной функции, когда список args пустой.
Параметры:
Template шаблон для частичного применения
args связываемые аргументы
Возвращает:
Шаблон, у которого количество аргументов меньше или равно Template
Примеры:
// enum bool isImplicitlyConvertible(From, To)
import std.traits : isImplicitlyConvertible;

static assert(allSatisfy!(
    ApplyLeft!(isImplicitlyConvertible, ubyte),
    short, ushort, int, uint, long, ulong));

static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short),
    ubyte, string, short, float, int) == AliasSeq!(ubyte, short)));
Примеры:
import std.traits : hasMember, ifTestable;

struct T1
{
    bool foo;
}

struct T2
{
    struct Test
    {
        bool opCast(T : bool)() { return true; }
    }

    Test foo;
}

static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2));
static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2));
Примеры:
import std.traits : Largest;

alias Types = AliasSeq!(byte, short, int, long);

static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) ==
            AliasSeq!(short, short, int, long)));
static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) ==
            AliasSeq!(int, int, int, long)));
Примеры:
import std.traits : FunctionAttribute, SetFunctionAttributes;

static void foo() @system;
static int bar(int) @system;

alias SafeFunctions = AliasSeq!(
    void function() @safe,
    int function(int) @safe);

static assert(is(staticMap!(ApplyRight!(
    SetFunctionAttributes, "D", FunctionAttribute.safe),
    typeof(&foo), typeof(&bar)) == SafeFunctions));
template Repeat(size_t n, TList...) if (n > 0)
Создает AliasSeq, который повторяет тип или AliasSeq точно n раз.
Примеры:
alias ImInt1 = Repeat!(1, immutable(int));
static assert(is(ImInt1 == AliasSeq!(immutable(int))));

alias Real3 = Repeat!(3, real);
static assert(is(Real3 == AliasSeq!(real, real, real)));

alias Real12 = Repeat!(4, Real3);
static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real,
    real, real, real, real, real, real)));

alias Composite = AliasSeq!(uint, int);
alias Composite2 = Repeat!(2, Composite);
static assert(is(Composite2 == AliasSeq!(uint, int, uint, int)));
Примеры:
auto staticArray(T, size_t n)(Repeat!(n, T) elems)
{
    T[n] a = [elems];
    return a;
}

auto a = staticArray!(long, 3)(3, 1, 4);
assert(is(typeof(a) == long[3]));
assert(a == [3, 1, 4]);
template staticSort(alias cmp, Seq...)
Сортирует AliasSeq используя cmp.

Параметры: cmp = Шаблон, который возвращает bool (если первый аргумент меньше, чем второй) или int (-1 означает меньше, 0 означает равенство, 1 означает больше)

Seq = AliasSeq для сортировки

Возвращает:
Отсортированная последовательность псевдонимов
Примеры:
alias Nums = AliasSeq!(7, 2, 3, 23);
enum Comp(int N1, int N2) = N1 < N2;
static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums));
Примеры:
alias Types = AliasSeq!(uint, short, ubyte, long, ulong);
enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1);
static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp,
    Types)));