S
不是一个类型。它是一个类型的模板。S!(5, 4)
是一种类型。很可能不同的实例S
产生完全地不同的代码,所以定义S!(5, 4)
可能完全地不同于S!(2, 5)
。例如,S
可能
struct S(int a, int b)
{
static if(a > 3)
string foo;
static if(b == 4)
int boz = 17;
else
float boz = 2.1;
}
请注意,成员变量的数量和类型不同,因此您不能真正使用S!(5, 4)
代替一个S!(2, 5)
。它们也可能是名为的结构U
and V
对于它们之间真正存在的所有关系来说,它们根本没有被模板化。
现在,特定模板的不同实例在 API 方面通常是相似的(或者它们可能不会使用相同的模板来完成),但从编译器的角度来看,它们彼此没有关系。因此,处理它的正常方法是纯粹对类型的 API 使用约束,而不是对其名称或实例化的模板使用约束。
所以,如果你期望S
具有以下功能foo
, bar
, and foozle
,而你想要你的fun
要使用这些函数,那么您将构造一个约束来测试赋予的类型fun
具有这些功能并且它们按预期工作。例如
void fun(T)(T t)
if(is({ auto a = t.foo(); t.bar(a); int i = t.foozle("hello", 22);}))
{}
然后任何具有称为函数的类型foo
它返回一个值,一个名为的函数bar
它可能会或可能不会返回一个值,并且其结果是foo
,以及一个名为foozle
这需要一个string
and an int
并返回一个int
将编译fun
. So, fun
比您坚持只进行实例化要灵活得多S
。在大多数情况下,此类约束被分成单独的同名模板(例如isForwardRange
or isDynamicArray
)而不是将原始代码放入is expression
这样它们就可以重用(并且更加用户友好),但是类似的表达式是此类同名模板在内部使用的。
现在,如果你really坚持约束fun
这样它只适用于实例化S
,那么我知道有两个选项。
1.添加某种声明S
总是有,而且你不希望任何其他类型有。例如
struct S(int a, int b)
{
enum isS = true;
}
void fun(T)(T t)
if(is(typeof(T.isS)))
{}
请注意,声明的实际值并不重要(其类型也不重要)。这是一个简单的事实,即您正在测试它的存在。
2.更优雅(但不太明显的解决方案)是这样做:
struct S(int a, int b)
{
}
void fun(T)(T t)
if(is(T u : S!(i, j), int i, int j))
{}
is表达式 http://dlang.org/expression.html#IsExpression一旦变得非常复杂,就有接近巫毒的倾向,但带逗号的版本正是您所需要的。这T u
是您正在测试的类型和标识符;这: S!(i, j)
给出您想要的模板专业化T
是一个实例;剩下的就是TemplateParameterList
声明在左侧的内容中使用但之前尚未声明的符号 - 在这种情况下,i
and j
.