On 21.08.19 01:48, ads wrote:
This piece of code creates a fizzbuzz string with template parameters.

auto fizzbuzz(uint N)() {
     string accumulate;
     return fizzbuzz!N(accumulate);
}

auto fizzbuzz(uint N)(ref string result) if (N % 3 && N % 5) {
     import std.conv : to;

     result ~= N.to!string ~ "\n";
     return fizzbuzz!(N - 1)(result);
}
[...]
void main() {
     import std.stdio : writeln;

     fizzbuzz!50().writeln();
}


https://godbolt.org/z/hWENgc

In the generated assembly, it looks like it is creating a lot of runtime instructions, contrary to my belief that templated codes are purely compile-time. I was expecting that the compiler would deduce the fizzbuzz string until 50 in compile-time and just print it in the run-time. Why is this not the case?

What you have there are function templates. You're generating functions at compile time, and then you're calling those generated functions at run time.

To do it all at compile time, you can skip the "functions" part and generate the result directly:

    template fizzbuzz(uint N) if (N % 3 && N % 5)
    {
        import std.conv : to;
        enum fizzbuzz = N.to!string ~ "\n" ~ fizzbuzz!(N - 1);
    }
    /* ... etc ... */

You won't be able to use an accumulator, because mutation like that doesn't mix with templates.

Alternatively, you can skip the "templates" part and call normal functions at compile time (CTFE):

    auto fizzbuzz(uint N)
    {
        string accumulate;
        return fizzbuzz(N, accumulate);
    }
    auto fizzbuzz(uint N, ref string result)
    {
        import std.conv : to;
        if (N % 3 && N % 5) result ~= N.to!string ~ "\n";
        /* ... etc ... */
    }
    void main()
    {
        import std.stdio : writeln;
        enum fz = fizzbuzz(50);
        writeln(fz);
    }

Reply via email to