static_foreach - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Discord (community-run)
  - Forums
  - IRC
  - Wiki
  - Issues
  - Contributing
  - 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.

# static_foreach

We saw compile-time `foreach` earlier in the Tuples chapter. Compile-time `foreach` iterates the loop at compile time and unrolls each iteration as separate pieces of code. For example, given the following `foreach` loop over a tuple:

        auto t = tuple(42, "hello", 1.5);

        foreach (i, member; t) {
            writefln("%s: %s", i, member);
        }

The compiler unrolls the loop similar to the following equivalent code:

        {
            enum size_t i = 0;
            int member = t[i];
            writefln("%s: %s", i, member);
        }
        {
            enum size_t i = 1;
            string member = t[i];
            writefln("%s: %s", i, member);
        }
        {
            enum size_t i = 2;
            double member = t[i];
            writefln("%s: %s", i, member);
        }

Although being very powerful, some properties of compile-time `foreach` may not be suitable in some cases:

- With compile-time `foreach`, each unrolling of the loop introduces a scope. As seen with the `i` and `member` variables above, this allows the use of a symbol in more than one scope without causing a multiple definition error. Although this can be desirable in some cases, it makes it impossible for code unrolled for one iteration to use code from other iterations.
- Compile-time `foreach` works only with tuples (including template arguments in the form of `AliasSeq`). For example, despite the elements of the following array literal being known at compile time, the loop will always be executed at run time (this may very well be the desired behavior):

    void main() {
        enum arr = [1, 2];
        // Executed at run time, not unrolled at compile time:
        foreach (i; arr) {
            // ...
        }
    }

- Like regular `foreach`, compile-time `foreach` can only be used inside functions. For example, it cannot be used at module scope or inside a user-defined type definition.

    import std.meta;

    // Attempting to define function overloads at module scope:
    foreach (T; AliasSeq!(int, double)) {    // ← derleme HATASI
        T twoTimes(T arg) {
            return arg * 2;
        }
    }

    void main() {
    }

    Error: declaration expected, not foreach

- With compile-time `foreach`, it may not be clear whether `break` and `continue` statements inside the loop body should affect the compile-time loop iteration itself or whether they should be parts of the unrolled code.

`static foreach` is a more powerful compile-time feature that provides more control:

- `static foreach` can work with any range of elements that can be computed at compile time (including number ranges like `1..10`). For example, given the `FibonacciSeries` range from the Ranges chapter and a function that determines whether a number is even:

        static foreach (n; FibonacciSeries().take(10).filter!isEven) {
            writeln(n);
        }

The loop above would be unrolled as the following equivalent:

        writeln(0);
        writeln(2);
        writeln(8);
        writeln(34);

- `static foreach` can be used at module scope.
- `static foreach` does not introduce a separate scope for each iteration. For example, the following loop defines two overloads of a function at module scope:

    import std.meta;

    static foreach (T; AliasSeq!(int, double)) {
        T twoTimes(T arg) {
            return arg * 2;
        }
    }

    void main() {
    }

The loop above would be unrolled as its following equivalent:

        int twoTimes(int arg) {
            return arg * 2;
        }

        double twoTimes(double arg) {
            return arg * 2;
        }

- `break` and `continue` statements inside a `static foreach` loop require labels for clarity. For example, the following code unrolls (generates) `case` clauses inside a `switch` statement. The `break` statements that are under each `case` clause must mention the associated `switch` statements by labels:

    import std.stdio;

    void main(string[] args) {

    theSwitchStatement:
        switch (args.length) {
            static foreach (i; 1..3) {
                case i:
                    writeln(i);
                    break theSwitchStatement;
            }

        default:
            writeln("default case");
            break;
        }
    }

After the loop above is unrolled, the `switch` statement would be the equivalent of the following code:

        switch (args.length) {
        case 1:
            writeln(1);
            break;

        case 2:
            writeln(2);
            break;

        default:
            writeln("default case");
            break;
        }

macros: TITLE=static foreach DESCRIPTION=static foreach, one of D's compile-time feature that can generate code by iterating ranges. KEYWORDS=d programming language tutorial book static foreach MINI_SOZLUK=
Copyright © 1999-2026 by the D Language Foundation | Page generated by Ddoc on Mon Aug 17 18:57:12 2026