Spec-Zone.ru › D

std.meta

Шаблоны для работы с последовательностями параметров шаблонов (также известными как последовательности псевдонимов).

Некоторые операции над последовательностями псевдонимов встроены в язык, например, S[i], который обращается к элементу с индексом i в последовательности. S[low .. high] возвращает новую последовательность псевдонимов, являющуюся срезем старой.

Для получения дополнительной информации, см. Последовательности во время компиляции.

Примечание: Несколько шаблонов в этом модуле используют или работают с одноимёнными шаблонами, которые принимают один аргумент и вычисляются в булево значение. Такие шаблоны называются предикатами шаблонов.

Категория Шаблоны
Основные элементы Alias AliasSeq aliasSeqOf
Фильтрация последовательностей псевдонимов Erase EraseAll Filter NoDuplicates Stride
Иерархия типов последовательностей псевдонимов DerivedToFront MostDerived
Преобразование последовательностей псевдонимов Repeat Replace ReplaceAll Reverse staticMap staticSort
Поиск в последовательностях псевдонимов allSatisfy anySatisfy staticIndexOf
Предикаты шаблонов templateAnd templateNot templateOr staticIsSorted
Инициализация шаблонов ApplyLeft ApplyRight Instantiate

Ссылки
Основано на идеях из Таблицы 3.1 из Modern C++ Design, Андрей Александреску (Addison-Wesley Professional, 2001)
Лицензия:
Лицензия Boost 1.0.
Авторы:
Уолтер Брайт, Дэвид Нэдлингер
Исходный код
std/meta.d
template AliasSeq(TList...)

Создаёт последовательность из нуля или более псевдонимов. Чаще всего используется в качестве параметров или аргументов шаблонов.

В предыдущих версиях Phobos это было известно как TypeTuple.

Примеры:
import std.meta;
alias TL = AliasSeq!(int, double);

int foo(TL td)  // same as 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)));
Примеры:
// Creates a compile-time sequence of function call expressions
// that each call `func` with the next variadic template argument
template Map(alias func, args...)
{
    auto ref lazyItem() {return func(args[0]);}

    static if (args.length == 1)
    {
        alias Map = lazyItem;
    }
    else
    {
        // recurse
        alias Map = AliasSeq!(lazyItem, Map!(func, args[1 .. $]));
    }
}

static void test(int a, int b)
{
    writeln(a); // 4
    writeln(b); // 16
}

static int a = 2;
static int b = 4;

test(Map!(i => i ^^ 2, a, b));
writeln(a); // 2
writeln(b); // 4

test(Map!((ref i) => i *= i, a, b));
writeln(a); // 4
writeln(b); // 16

static void testRef(ref int a, ref int b)
{
    writeln(a++); // 16
    writeln(b++); // 256
}

testRef(Map!(function ref(ref i) => i *= i, a, b));
writeln(a); // 17
writeln(b); // 257
template Alias(alias a)

template Alias(T)

Позволяет alias любого отдельного символа, типа или выражения времени компиляции.

Не всё может быть непосредственно проинициализировано псевдонимом. Псевдоним не может быть объявлен для, например, литерала:

alias a = 4; //Error
С помощью этого шаблона можно присвоить псевдоним любому отдельному элементу:
alias b = Alias!4; //OK

См. также:
Чтобы присвоить псевдоним нескольким вещам одновременно, используйте AliasSeq.
Примеры:
// Without Alias this would fail if Args[0] was e.g. a value and
// some logic would be needed to detect when to use enum instead
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;
writeln(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...)

Возвращает AliasSeq , созданную из 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...)

Возвращает AliasSeq , созданную из TList, с удалёнными всеми вхождениями T, если они есть.

Примеры:
alias Types = AliasSeq!(int, long, long, int);

alias TL = EraseAll!(long, Types);
static assert(is(TL == AliasSeq!(int, int)));
template NoDuplicates(TList...)

Возвращает AliasSeq , созданную из TList, со всеми дублирующими типами, удалёнными.

Примеры:
alias Types = AliasSeq!(int, long, long, int, float);

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

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

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

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

Возвращает AliasSeq , созданную из 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...)

Возвращает AliasSeq , созданную из 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...)

Возвращает AliasSeq , созданную из TList с обратным порядком.

Примеры:
alias Types = AliasSeq!(int, long, long, int, float, byte, ubyte, short, ushort, uint);

alias TL = Reverse!(Types);
static assert(is(TL == AliasSeq!(uint, ushort, short, ubyte, byte, float, int, long, long, int)));
template MostDerived(T, TList...)

Возвращает тип из TList, наиболее производный от типа T. Если не найдено, возвращается T.

Примеры:
class A { }
class B : A { }
class C : B { }
alias Types = AliasSeq!(A, C, B);

MostDerived!(Object, Types) x;  // x is declared as type C
static assert(is(typeof(x) == C));
template DerivedToFront(TList...)

Возвращает AliasSeq с элементами 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, Args...)

Вычисляется в AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1])).

Примеры:
import std.traits : Unqual;
alias TL = staticMap!(Unqual, int, const int, immutable int, uint, ubyte, byte, short, ushort);
static assert(is(TL == AliasSeq!(int, int, int, uint, ubyte, byte, short, ushort)));
template allSatisfy(alias F, T...)

Проверяет, удовлетворяют ли все заданные элементы заданному шаблонному предикату, т.е. вычисляется как F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).

Вычисление не производится по принципу короткого замыкания, если встречается ложное значение; шаблонный предикат должен быть применимым ко всем заданным элементам.

Примеры:
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]).

Вычисление производится по принципу короткого замыкания, если встречается истинное значение; шаблонный предикат должен быть применимым к одному из заданных элементов.

Примеры:
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);

// An empty sequence of predicates always yields 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));

// An empty sequence of predicates never yields true.
alias alwaysFalse = templateOr!();
static assert(!alwaysFalse!int);
template aliasSeqOf(alias iter) if (isIterable!(typeof(iter)) && !isInfinite!(typeof(iter)))

Преобразует любой итерируемый по foreach элемент (например, диапазон входных данных) в последовательность псевдонимов.

Параметры:
iter элемент, который нужно преобразовать в AliasSeq. Он должен быть итерируемым по foreach-циклу.
Возвращает:
Последовательность AliasSeq , содержащую значения, полученные путём итерирования по iter.
Примеры:
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 путём привязки его первого (слева) или последнего (справа) аргументов к args.

Ведёт себя как функция тождества, когда args пусто.

Параметры:
Template шаблон для частичного применения
args аргументы для привязки
Возвращает:
Template с арностью меньше или равной 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...)

Создаёт AliasSeq , который повторяет TList ровно n раз.

Примеры:
alias ImInt0 = Repeat!(0, int);
static assert(is(ImInt0 == AliasSeq!()));

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)));

alias ImInt10 = Repeat!(10, int);
static assert(is(ImInt10 == AliasSeq!(int, int, int, int, int, int, int, int, int, 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]));
writeln(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)));
template staticIsSorted(alias cmp, Seq...)

Проверяет, является ли AliasSeq отсортированной по cmp.

Параметры
cmp = Шаблон, который возвращает bool (если его первый аргумент меньше второго) или int (-1 означает меньше, 0 означает равно, 1 означает больше)
Seq = AliasSeq для проверки
Возвращает:
true если Seq отсортирована; в противном случае false
Примеры:
enum Comp(int N1, int N2) = N1 < N2;
static assert( staticIsSorted!(Comp, 2, 2));
static assert( staticIsSorted!(Comp, 2, 3, 7, 23));
static assert(!staticIsSorted!(Comp, 7, 2, 3, 23));
Примеры:
enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1);
static assert( staticIsSorted!(Comp, uint, ubyte, ulong, short, long));
static assert(!staticIsSorted!(Comp, uint, short, ubyte, long, ulong));
template Stride(int stepSize, Args...) if (stepSize != 0)

Выбирает подмножество Args, шагая с фиксированным stepSize по последовательности. Отрицательное stepSize начинает итерацию с последнего элемента.

Параметры:
stepSize Количество элементов, на которое увеличивается индекс при каждой итерации. Не может быть 0.
Args Шаблоны аргументов.
Возвращает:
Отфильтрованное AliasSeq с выбранным шагом.
Примеры:
static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long)));
static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long)));
static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short)));
static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short)));

alias attribs = AliasSeq!(short, int, long, ushort, uint, ulong);
static assert(is(Stride!(3, attribs) == AliasSeq!(short, ushort)));
static assert(is(Stride!(3, attribs[1 .. $]) == AliasSeq!(int, uint)));
static assert(is(Stride!(-3, attribs) == AliasSeq!(ulong, long)));
template Instantiate(alias Template, Params...)

Инициализирует данный шаблон с заданными параметрами.

Используется для обхода синтаксических ограничений D в отношении инициализации шаблона из последовательности псевдонимов (например, T[0]!(...) недопустимо) или шаблона, возвращающего другой шаблон (например, Foo!(Bar)!(Baz) запрещено).

Параметры:
Template Шаблон для инициализации.
Params Параметры для инициализации шаблона.
Возвращает:
Инициализированный шаблон.
Примеры:
// ApplyRight combined with Instantiate can be used to apply various
// templates to the same parameters.
import std.string : leftJustify, center, rightJustify;
alias functions = staticMap!(ApplyRight!(Instantiate, string),
                             leftJustify, center, rightJustify);
string result = "";
static foreach (f; functions)
{
    {
        auto x = &f; // not a template, but a function instantiation
        result ~= x("hello", 7);
        result ~= ";";
    }
}

writeln(result); // "hello  ; hello ;  hello;"

© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_meta.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API