Movatterモバイル変換


[0]ホーム

URL:


D Logo
Menu
Search

Articles

overview

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 usinga local clone.

Compile-time Sequences

Contents
  1. Background
  2. AliasSeq
  3. Available operations
    1. Checking the length
    2. Indexing and slicing
    3. foreach
  4. Auto-expansion
  5. Homogenous sequences
    1. Type sequences
    2. Type sequence instantiation
    3. Value sequences
    4. Symbol sequences

Background

Compile-time sequences are an important metaprogramming concept that comes naturally from D support forvariadic templates. They allow a programmer to operate on types, symbols and values, enabling the ability to define compile-time algorithms that operate on types, symbols and values.

Note: For historical reasons these sequences can sometimes be called tuples in documentation or compiler internals, but don't get confused - they don't have much in common with tuples that commonly exist in other languages. Sequences of values of different types that can be returned from functions are provided bystd.typecons.Tuple. Using the term "tuple" to mean compile-time sequences is discouraged to avoid confusion, and if encountered should result in adocumentation bug report.

Consider this simple variadic template:

template Variadic(T...) {/* ... */ }

T here is aTemplateParameterSequence, which is a core language feature. It has its own special semantics, and, from the programmer's point of view, is most similar to an array of compile-time entities - types, symbols (names) and values. One can check the length of this sequence and access any individual element:

template Variadic(T...){staticassert(T.length > 1);pragma(msg, T[0]);pragma(msg, T[1]);}alias dummy = Variadic!(int, 42);

Output during compilation:

int42

AliasSeq

The language itself does not provide any means to define such sequences outside of a template parameter declaration. Instead, there is asimple template provided by the standard library:

alias AliasSeq(T...) = T;

All it does is give a specific variadic argument sequence an externally accessible name so that it can be worked with in any other context:

import std.meta;// can alias to some other namealias Name = AliasSeq!(int, 42);pragma(msg, Name[0]);// intpragma(msg, Name[1]);// 42// or work with a sequence directlypragma(msg, AliasSeq!("aaa", 0,double)[2]);// double

Available operations

Checking the length

import std.meta;staticassert(AliasSeq!(1, 2, 3, 4).length == 4);

Indexing and slicing

Indexes must be known at compile-time

import std.meta;alias nums = AliasSeq!(1, 2, 3, 4);staticassert(nums[1] == 2);// slice last 3 elementsalias tail = nums[1 .. $];staticassert(tail[0] == 2);staticassert(tail.length == 3);

Element assignment

Works only if the sequence element is a symbol that refers to a mutable variable

import std.meta;void main(){int x;alias seq = AliasSeq!(10, x);    seq[1] = 42;assert(x == 42);// seq[0] = 42; // won't compile, can't assign to a constant}

foreach

D'sforeach statement has special semantics when iterating over compile-time sequences. It repeats the body of the loop for each of the sequence elements, with the loop iteration symbol being an alias for each compile-time sequence element in turn.

import std.meta;void main(){foreach (sym; AliasSeq!(int,"literal", main))    {staticif (is(sym))pragma (msg, sym);elsepragma (msg,typeof(sym));    }}

Output during compilation:

intstringvoid()

Note:Static foreach should be preferred in new code.

Auto-expansion

One less obvious property of compile-time argument sequences is that when used as an argument to a function or template, they are automatically treated as a sequence of comma-separated arguments:

import std.meta;template Print0(T...){pragma(msg, T[0]);}alias Dummy = Print0!(AliasSeq!(int,double));

This will only printint during compilation because the last line gets rewritten asalias Dummy = Print0!(int, double). If auto-expansion didn't happen,AliasSeq!(int, double) would be printed instead. This is an inherent part of the language semantics for variadic sequences, and thus also preserved byAliasSeq.

Homogenous sequences

AnAliasSeq that consists of only type or value elements are commonly called "type sequences" or "value sequences" respectively. The concept of a "symbol sequence" is used less frequently but fits the same pattern.

Type sequences

It is possible to use homogenous type sequences in declarations:

import std.meta;alias Params = AliasSeq!(int,double, string);void foo(Params);// void foo(int, double, string);foo(7, 6.5,"hi");

Type sequence instantiation

D supports a special variable declaration syntax where a type sequence acts as a type:

import std.meta;void foo(){    AliasSeq!(int,double, string) variables;    variables[0] = 42;    variables[1] = 42.0;    variables[2] ="just a normal variable";}

The compiler will rewrite such a declaration to something like this:

int __var1;double __var2;string __var3;alias variables = AliasSeq!(__var1, __var2, __var3);

So a type sequence instance is a kind of symbol sequence that only aliases variables, known as anlvalue sequence.

Variadic template functions use a type sequence instance to declare function parameters:

void foo(T...)(T args){// 'T' is a type sequence of argument types.// 'args' is an instance of T whose elements are the function parametersstaticassert(is(typeof(args) == T));    args[0] = T[0].init;}

Value sequences

It is possible to use a sequence of values of the same type to declare an array literal:

import std.meta;enum e = 3;enum arr = [ AliasSeq!(1, 2, e) ];staticassert(arr == [ 1, 2, 3 ]);

The above sequence is anrvalue sequence, as it is comprised only of literal values and manifest constants. Each element's value is known at compile-time.

The following demonstrates use of anlvalue sequence:

import std.meta, std.algorithm;auto x = 3, y = 7;alias pair = AliasSeq!(x, y);swap(pair);assert(x == 7 && y == 3);

As above, such sequences may useelement assignment.

.tupleof is a class/struct instance property that provides an lvalue sequence of each field.

A function cannot return a value sequence. Instead,std.typecons.Tuple can be used. It wraps an lvalue sequence in a struct, preventing auto-expansion.

Symbol sequences

A symbol sequence aliases any named symbol - types, variables, functions and templates -but not literals.Like an alias sequence, the kind of elements can be mixed.

import std.meta : AliasSeq;void f(T)(T v){pragma(msg, T);}alias syms = AliasSeq!(f, f!byte);syms[0](42);// call f!int with IFTIsyms[1](42);// call f!byte

Output during compilation:

byteint

Note that functionf!byte is instantiated when the sequence iscreated, not at the call-site.

Copyright © 1999-2026 by theD Language Foundation | Page generated byDdoc on Sat Feb 21 00:13:47 2026

[8]ページ先頭

©2009-2026 Movatter.jp