通常,如果您需要限制模板可以採用的內容,則可以使用模板約束。例如
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