Reputation: 3140
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
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
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