使用模板指定一个函数,该函数接受和 returns 任意 class
Specifying a function with templates that takes and returns an arbitrary class
我有兴趣定义一个函数,给定一个 class 变量,生成一个 class 对象的新实例,其中随机选择的成员属性发生变异。
上下文:考虑一些 class、Circle
的实例 circle1
,具有属性 color
和 radius
。这些属性的赋值分别为 red
和 5
。有问题的函数 mutate
必须接受 circle1
作为参数,但拒绝非 class 参数。
对于其他数据类型,模板在此上下文中提供了答案。也就是说,模板可用于指定可以接受多种类型参数的函数的通用实例。
如何使用模板定义接受(和returns)任何class实例的通用函数?
一般来说,如果您需要限制模板可以采用的内容,您可以使用模板约束。例如
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
has quite a few overloads all of which are differentiated by template constraint). The built-in __traits
, the eponymous templates in std.traits
, and is
expressions provide quite a few tools for testing stuff at compile time and then using that information in template constraints or static if
条件。
如果您特别想测试某物是否为 class,则使用带有 == class
的 is
表达式。例如
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))
{
...
}
如果条件是您想要重复使用的东西,那么创建一个同名模板是有意义的 - 这就是在 Phobos 中所做的事情,例如 std.range.primitives and std.range.traits. For instance, to test for an input range, 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
}));
}
然后需要输入范围的代码可以使用它。所以,Phobos 中的很多函数都有类似
的东西
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))
{
...
}
Ali Ç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
我有兴趣定义一个函数,给定一个 class 变量,生成一个 class 对象的新实例,其中随机选择的成员属性发生变异。
上下文:考虑一些 class、Circle
的实例 circle1
,具有属性 color
和 radius
。这些属性的赋值分别为 red
和 5
。有问题的函数 mutate
必须接受 circle1
作为参数,但拒绝非 class 参数。
对于其他数据类型,模板在此上下文中提供了答案。也就是说,模板可用于指定可以接受多种类型参数的函数的通用实例。
如何使用模板定义接受(和returns)任何class实例的通用函数?
一般来说,如果您需要限制模板可以采用的内容,您可以使用模板约束。例如
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
has quite a few overloads all of which are differentiated by template constraint). The built-in __traits
, the eponymous templates in std.traits
, and is
expressions provide quite a few tools for testing stuff at compile time and then using that information in template constraints or static if
条件。
如果您特别想测试某物是否为 class,则使用带有 == class
的 is
表达式。例如
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))
{
...
}
如果条件是您想要重复使用的东西,那么创建一个同名模板是有意义的 - 这就是在 Phobos 中所做的事情,例如 std.range.primitives and std.range.traits. For instance, to test for an input range, 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
}));
}
然后需要输入范围的代码可以使用它。所以,Phobos 中的很多函数都有类似
的东西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))
{
...
}
Ali Ç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