D的概念
D语言中的模板约束是该语言最出色的功能之一.然而,当约束失败时,很难知道它失败的原因.该库提供一个说明用户自定义类型应实现编译时接口或概念的方式来解决它.
如isInputRange.如果你不小心把空的拼成了empt,你的类型就不是输入区间,但尽管编译器知道,你也不知道为什么.
解决方法是使用可按UDA也可按静断使用的模型.
cpp
import concepts.models: models;
void checkFoo(T)()
{
T t = T.init;
t.foo();
}
enum isFoo(T) = is(typeof(checkFoo!T));
@models!(Foo, isFoo)
//按`UDA`
struct Foo
{
void foo() {}
static assert(models!(Foo, isFoo));
//按静断
}
//仍可用作`模板约束`:
void useFoo(T)(auto ref T foo) if(isFoo!T) {
}
这里模板约束isFoo保证对福类型成立.这与普通静断的区别在于,当动作失败时,checkFoo的代码仍会实例化,这样用户就知道它为何未能成功编译.dmd2.074示例错误信息:
cpp
source/concepts/models.d(111,10): Error: no property 'foo' for type 'Foo', did you mean 'fo'
source/concepts/models.dmixin-42(42,1): Error: template instance concepts.models.checkFoo!(Foo) error instantiating
source/concepts/models.d(61,6): instantiated from here: models!(Foo, isFoo)
该库还实现了d标准库的区间模板约束版本,使其可用在模型上:
cpp
import concepts: models, isInputRange;
@models!(Foo, isInputRange)
struct Foo {
//...
}
dmd2.074示例错误信息(已实现front和popFront但未实现empty):
cpp
source/concepts/range.d(13,10): Error: template std.range.primitives.empty cannot deduce function from argument types !()(B), candidates are:
/usr/include/dlang/dmd/std/range/primitives.d(2043,16): std.range.primitives.empty(T)(in T[] a)
source/concepts/models.dmixin-42(42,1): Error: template instance concepts.range.checkInputRange!(B) error instantiating
source/concepts/range.d(72,6): instantiated from here: models!(B, isInputRange)
使用D接口指定编译时模板约束
cpp
interface IFoo {
int foo(int i, string s) @safe;
double lefoo(string s) @safe;
}
@implements!(Foo, IFoo)
struct Foo {
int foo(int i, string s) @safe { return 0; }
double lefoo(string s) @safe { return 0; }
}
//如下,无法编译
@implements!(Oops, IFoo)
struct Oops {}
其他示例
限制结构不包含成员函数(感谢@jmh530):
cpp
void checkOnlyData(T)()
if (is(T == struct))
{
import std.traits : isFunction;
static foreach (mem; __traits(allMembers, T))
{
static if (mem != "this")
{
static assert(!(isFunction!(__traits(getMember, T.init, mem))),
T.stringof ~ " is constrained to not have any member functions, but it has (at least) the member function: " ~ mem);
}
}
}
template isOnlyData(T)
if (is(T == struct))
{
enum isOnlyData = is(typeof(checkOnlyData!(T)));
}
@models!(Foo, isOnlyData)
struct Foo
{
int a;
}
Foo foo;