Koz Ross
Koz Ross

Reputation: 3140

Are variadic mixin templates possible in D?

Suppose I need to do something similar to this:

mixin(some_template!("x", "foo"));

mixin(some_template!("x", "bar"));

mixin(some_template!("x", "baz"));

mixin(some_template!("y", "foo"));

mixin(some_template!("y", "bar"));

mixin(some_template!("z", "baz"));

Is it somehow possible to create another_template which is a variadic version of some_template, where you can give anywhere from 2 to however-many arguments? What I mean is that I would like to be able to say:

mixin(another_template!("x", "foo", "bar", "baz"));

mixin(another_template!("y", "foo", "bar"));

mixin(another_template!("z", "baz"));

and have it expand to equivalent code to what the first example would expand to.

Upvotes: 4

Views: 271

Answers (2)

Vladimir Panteleev
Vladimir Panteleev

Reputation: 25187

This answer assumes you really meant template mixins, and not templated functions.

Yes, you can declare variadic template parameters, e.g.:

mixin template another_template(string A, Bs...)

Then, you can use static if and recursive instantiation to process the whole list.

Full example:

mixin template some_template(string A, string B)
{
    pragma(msg, "some_template: " ~ A ~ ", " ~ B);
}

mixin template another_template(string A, Bs...)
{
    mixin some_template!(A, Bs[0]);
    static if (Bs.length > 1)
        mixin another_template!(A, Bs[1..$]);
}

mixin another_template!("x", "foo", "bar", "baz");

mixin another_template!("y", "foo", "bar");

mixin another_template!("z", "baz");

Upvotes: 6

Adam D. Ruppe
Adam D. Ruppe

Reputation: 25595

Yes, using the regular variadic template syntax (Something... collects the rest of the template arguments given and they can be of mixed types. see: http://dlang.org/template#TemplateTupleParameter):

string some_template(strings...)() {
        string a;
        foreach(f; strings)
                a ~= f;
        return a;
}

void main() {
        mixin(some_template!("int ", "giggle", ";"));
}

You can restrict the type with a constraint like this:

// this condition will only compile if it is passed a string
import std.typetuple;
enum check_if_string(string s) = true;

// then we check that they all compile with the check_if_string check
string some_template(strings...)() if(allSatisfy!(check_if_string, strings)) {
        string a;
        foreach(f; strings)
                a ~= f;
        return a;
}

The error message will be ugly though, and non-strings won't compile even without this check so it isn't really important. But you can also use the if check in there for like if(strings.length >= 2) as well.

This is called a template constraint: http://dlang.org/template#Constraint

Upvotes: 8

Related Questions