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 означает больше)
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 означает больше)
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