通常,如果您需要限制模板可以采用的内容,则可以使用模板约束。例如
import std.traits : isIntegral;
auto foo(T)(T t)
if(isIntegeral!T)
{
...
}
或
import std.functional : binaryFun;
auto foo(alias pred, T, U)(T t, U u)
if(is(typeof(binaryFun!pred(t, u.bar())) == bool)
{
...
}
只要条件可以在编译时进行检查,可以测试几乎任何东西。它也可以用于函数重载(例如std.algorithm.searching.find
有相当多的重载,所有这些重载都是通过模板约束来区分的)。内置的__traits
,std.traits
和is
expressions中的同名模板提供了很多工具,用于在编译时测试内容,然后在模板约束或static if
条件下使用该信息。
如果您特别想测试某种类是否是某种类型,请使用is
表达式与== class
。例如
auto foo(T)(T t)
if(is(T == class))
{
...
}
虽然在一般,你可能会想使用诸如__traits(compiles, MyType result = t.foo(22))
或is(typeof(t.foo(22)) == MyType)
更具体的条件。所以,你可以有像
auto mutate(T)(T t)
if(is(T == class) &&
__traits(compiles, t.color = red) &&
__traits(compiles, t.radius = 5))
{
...
}
如果条件是要重复使用的东西,那么它可以是有意义的创建一个同名的模板 - 这是什么在火卫一进行的地方,如std.range.primitives和std.range.traits。例如,要测试的输入范围,std.range.primitives.isInputRange
看起来像
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = R.init; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
然后代码需要的输入范围可以使用。所以,很多功能在火卫一有这样的东西
auto foo(R)(R range)
if(isInputRange!R)
{
...
}
更具体的例子是该超载find
:
InputRange find(alias pred = "a == b", InputRange, Element)
(InputRange haystack, Element needle)
if(isInputRange!InputRange &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{
...
}
阿里Çehreli的书,Programming in D,有几个相关章节,包括:
http://ddili.org/ders/d.en/templates.html
http://ddili.org/ders/d.en/cond_comp.html
http://ddili.org/ders/d.en/is_expr.html
http://ddili.org/ders/d.en/templates_more.html