struct S(int a, int b) { }
void fun(T)(T t) { }
Run Code Online (Sandbox Code Playgroud)
我只想和你fun一起工作S.签名约束会是什么样的?
我不能成为fun会员S,而且void fun(T)(T t) if(is(T : S)) { }我得到了Error: struct t1.S(int a,int b) is used as a type
Jon*_*vis 10
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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,成员变量的数量和类型不同,因此您无法真正使用S!(5, 4)代替变量S!(2, 5).他们可能也被命名为结构U,V并且对于他们真正彼此之间的所有关系而言,它们根本没有被模板化.
现在,特定模板的不同实例化关于它们的API通常是相似的(或者它们可能不会使用相同的模板完成),但是从编译器的角度来看,它们彼此没有关系.因此,处理它的常用方法是纯粹在类型的API上使用约束,而不是在其名称或实例化的模板上使用约束.
所以,如果你希望S有函数foo,bar和foozle,并且你希望你fun使用这些函数,那么你将构造一个约束来测试给定的类型是否fun具有这些函数并且它们按预期工作.例如
void fun(T)(T t)
if(is({ auto a = t.foo(); t.bar(a); int i = t.foozle("hello", 22);}))
{}
Run Code Online (Sandbox Code Playgroud)
然后任何具有调用函数的类型foo返回一个值,一个名称bar可能会返回一个值并且不会返回一个值foo的函数,并且一个函数名为foozlea string和a int并且返回一个int将编译的函数fun.因此,fun比你坚持只采取实例化更灵活S.在大多数情况下,这种限制被分离成单独的名字命名的模板(如isForwardRange或isDynamicArray),而不是把原始代码以is expression使它们是可重复使用(多用户友好的),但这样的表现是什么,例如同名的模板内部使用.
现在,如果你真的坚持限制fun它只适用于实例化S,那么我有两个选项.
1.添加一种S始终具有的某种声明,并且您不希望任何其他类型的声明.例如
struct S(int a, int b)
{
enum isS = true;
}
void fun(T)(T t)
if(is(typeof(T.isS)))
{}
Run Code Online (Sandbox Code Playgroud)
请注意,声明的实际值无关紧要(也不是其类型).这是一个简单的事实,它存在你正在测试.
2.更优雅(但不那么明显的解决方案)是这样做:
struct S(int a, int b)
{
}
void fun(T)(T t)
if(is(T u : S!(i, j), int i, int j))
{}
Run Code Online (Sandbox Code Playgroud)
is一旦它们变得非常复杂,表达式就会倾向于接受伏都教的边界,但带有逗号的版本正是你所需要的.这T u是您正在测试的类型和标识符; 该: S!(i, j)给你想要的模板专业化T是的一个实例; 其余的是TemplateParameterList声明在左边的东西中使用的符号,但之前没有声明过的符号 - 在这种情况下,i和j.
我认为在其他答案中有一些小红色鲱鱼.您可以使用模式匹配来确定T是否是S的某个实例,如下所示.
最简单的方法是对参数本身进行模式匹配:
void fun(int a, int b)(S!(a, b) t) {
}
Run Code Online (Sandbox Code Playgroud)
更一般地说,您可以在模板约束内的模式匹配中进行模式匹配:
void fun(T)(T t) if (is(T U == S!(a, b), int a, int b)) {
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,您都可以访问实例化参数.