Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Forums
  - IRC
  - Community Discord
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# std.meta

Templates to manipulate template parameter sequences (also known as alias sequences).
Some operations on alias sequences are built into the language, such as S[i], which accesses the element at index i in the sequence. S[low .. high] returns a new alias sequence that is a slice of the old one.
For more information, see Compile-time Sequences.
Note: Several templates in this module use or operate on eponymous templates that take a single argument and evaluate to a boolean constant. Such templates are referred to as template predicates.

Category | Templates
--- | ---
Building blocks | Alias AliasSeq aliasSeqOf
Alias sequence filtering | Erase EraseAll Filter NoDuplicates Stride
Alias sequence type hierarchy | DerivedToFront MostDerived
Alias sequence transformation | Repeat Replace ReplaceAll Reverse staticMap staticSort
Alias sequence searching | allSatisfy anySatisfy staticIndexOf
Template predicates | templateAnd templateNot templateOr staticIsSorted
Template instantiation | ApplyLeft ApplyRight Instantiate

References Based on ideas in Table 3.1 from Modern C++ Design, Andrei Alexandrescu (Addison-Wesley Professional, 2001)

License:
Boost License 1.0.
Authors:
Walter Bright, David Nadlinger

Source std/meta.d

template `AliasSeq`(TList...)
  Creates a sequence of zero or more aliases. This is most commonly used as template parameters or arguments.
  In previous versions of Phobos, this was known as TypeTuple.
  Examples:

      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];
      }

  Examples:

      alias TL = AliasSeq!(int, double);

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

  Examples:

      // 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)
  Allows aliasing of any single symbol, type or compile-time expression.
  Not everything can be directly aliased. An alias cannot be declared of - for example - a literal:

      alias a = 4; //Error

  With this template any single entity can be aliased:

      alias b = Alias!4; //OK

  See Also:
  To alias more than one thing at once, use AliasSeq.
  Examples:

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

  Examples:

      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

template `staticIndexOf`(args...) if (args.length >= 1)
  Returns the index of the first occurrence of args[0] in the sequence args[1 .. $]. args may be types or compile-time values. If not found, -1 is returned.
  Examples:

      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`(args...) if (args.length >= 1)
  Returns an AliasSeq created from args[1 .. $] with the first occurrence, if any, of args[0] removed.
  Examples:

      alias Types = AliasSeq!(int, long, double, char);
      alias TL = Erase!(long, Types);
      static assert(is(TL == AliasSeq!(int, double, char)));

template `EraseAll`(args...) if (args.length >= 1)
  Returns an AliasSeq created from args[1 .. $] with all occurrences, if any, of args[0] removed.
  Examples:

      alias Types = AliasSeq!(int, long, long, int);
      static assert(is(EraseAll!(long, Types) == AliasSeq!(int, int)));

template `NoDuplicates`(args...)
  Returns an AliasSeq created from args with all duplicate types removed.
  Examples:

      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...)
  Returns an AliasSeq created from TList with the first occurrence of T, if found, replaced with U.
  Examples:

      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`(args...)
  Returns an AliasSeq created from args[2 .. $] with all occurrences of args[0], if any, replaced with args[1].
  Examples:

      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`(args...)
  Returns an AliasSeq created from args with the order reversed.
  Examples:

      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...)
  Returns the type from TList that is the most derived from type T. If no such type is found, T is returned.
  Examples:

      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...)
  Returns an AliasSeq with the elements of TList sorted so that the most derived types come first.
  Examples:

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

      alias TL2 = DerivedToFront!(A, A, A, B, B, B, C, C, C);
      static assert(is(TL2 == AliasSeq!(C, C, C, B, B, B, A, A, A)));

template `staticMap`(alias fun, args...)
  Evaluates to AliasSeq!(fun!(args[0]), fun!(args[1]), ..., fun!(args[$ - 1])).
  Examples:

      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...)
  Tests whether all given items satisfy a template predicate, i.e. evaluates to F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).
  Evaluation is not short-circuited if a false result is encountered; the template predicate must be instantiable with all the given items.
template `anySatisfy`(alias F, T...)
  Tests whether any given items satisfy a template predicate, i.e. evaluates to F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1]).
  Evaluation is short-circuited if a true result is encountered; the template predicate must be instantiable with one of the given items.
template `Filter`(alias pred, args...)
  Filters an AliasSeq using a template predicate. Returns an AliasSeq of the elements which satisfy the predicate.
  Examples:

      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)
  Negates the passed template predicate.
  Examples:

      import std.traits : isPointer;

      alias isNoPointer = templateNot!isPointer;
      static assert(!isNoPointer!(int*));
      static assert(allSatisfy!(isNoPointer, string, char, float));

template `templateAnd`(Preds...)
  Combines several template predicates using logical AND, i.e. constructs a new predicate which evaluates to true for a given input T if and only if all of the passed predicates are true for T.
  The predicates are evaluated from left to right, aborting evaluation in a short-cut manner if a false result is encountered, in which case the latter instantiations do not need to compile.
  Examples:

      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...)
  Combines several template predicates using logical OR, i.e. constructs a new predicate which evaluates to true for a given input T if and only at least one of the passed predicates is true for T.
  The predicates are evaluated from left to right, aborting evaluation in a short-cut manner if a true result is encountered, in which case the latter instantiations do not need to compile.
  Examples:

      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)))
  Converts any foreach-iterable entity (e.g. an input range) to an alias sequence.
  Parameters:

  iter | the entity to convert into an AliasSeq. It must be able to be able to be iterated over using a foreach-statement.

  Returns:
  An AliasSeq containing the values produced by iterating over iter.
  Examples:

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

  Examples:

      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...)
  Partially applies Template by binding its first (left) or last (right) arguments to args.
  Behaves like the identity function when args is empty.
  Parameters:

  Template | template to partially apply
  args | arguments to bind

  Returns:
  Template with arity smaller than or equal to Template
  Examples:

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

  Examples:

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

  Examples:

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

  Examples:

      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, items...)
  Creates an AliasSeq which repeats items exactly n times.
  Examples:

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

      alias Big = Repeat!(1_000_000, int);

  Examples:

      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, items...)
  Sorts an AliasSeq using cmp.

  Parameters cmp = A template that returns a bool (if its first argument is less than the second one) or an int (-1 means less than, 0 means equal, 1 means greater than)

  items = The AliasSeq to sort
  Returns:
  The sorted alias sequence
  Examples:

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

  Examples:

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

enum auto `staticIsSorted`(alias cmp, items...);
  Checks if an AliasSeq is sorted according to cmp.

  Parameters cmp = A template that returns a bool (if its first argument is less than the second one) or an int (-1 means less than, 0 means equal, 1 means greater than)

  Seq = The AliasSeq to check
  Returns:
  true if Seq is sorted; otherwise false
  Examples:

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

  Examples:

      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)
  Selects a subset of Args by stepping with fixed stepSize over the sequence. A negative stepSize starts iteration with the last element.
  Parameters:

  stepSize | Number of elements to increment on each iteration. Can't be 0.
  Args | Template arguments.

  Returns:
  An AliasSeq filtered by the selected stride.
  Examples:

      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...)
  Instantiates the given template with the given parameters.
  Used to work around syntactic limitations of D with regard to instantiating a template from an alias sequence (e.g. T[0]!(...) is not valid) or a template returning another template (e.g. Foo!(Bar)!(Baz) is not allowed).
  Parameters:

  Template | The template to instantiate.
  Params | The parameters with which to instantiate the template.

  Returns:
  The instantiated template.
  Examples:

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

Copyright © 1999-2023 by the D Language Foundation | Page generated by Ddoc on Sat Jul 15 12:03:57 2023