2012-07-07 103 views
4
struct S(int a, int b) { } 

void fun(T)(T t) { } 

我想要fun只与S一起使用。签名约束是什么样子的?通用类型的签名约束

我不能让funS成员,并与void fun(T)(T t) if(is(T : S)) { }我得到Error: struct t1.S(int a,int b) is used as a type

回答

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; 
} 

注意,成员变量的数量和类型的不同,使得你不能真正到位的S!(2, 5)的使用S!(5, 4)。它们也可能是名为UV的结构,它们完全没有被模板化,以至于它们彼此之间的所有关系都是模板化的。

现在,特定模板的不同实例通常与其API相似(或者它们可能不会用相同的模板完成),但从编译器的角度来看,它们彼此没有关系。因此,处理它的正常方式是纯粹使用类型的API而不是名称或实例化的模板。

所以,如果你希望S有功能foobarfoozle,并希望您的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函数,它接受一个stringint并返回intfun编译。因此,fun远比您坚持只采取S的实例更灵活。在大多数情况下,这种限制被分离成单独的名字命名的模板(如isForwardRangeisDynamicArray),而不是把原始代码在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))) 
{} 

注意,声明的实际值并不重要(也没有它的类型)。这是一个简单的事实,它存在,你正在测试。

2.更优雅(但远不明显的解决方案)是这样做:

struct S(int a, int b) 
{ 
} 

void fun(T)(T t) 
    if(is(T u : S!(i, j), int i, int j)) 
{} 

is expressions有一种倾向边境上的巫术,一旦他们变得非常复杂,但用逗号的版本正是你需要的。 T u是您正在测试的类型和标识符; : S!(i, j)给出了你想要T作为实例化的模板专门化;剩下的就是一个TemplateParameterList宣布其在玩艺到左侧,但先前没有被宣布为符号 - 在这种情况下,ij

+0

这里你不需要使用签名约束:'void fun(T:S!(i,j),int i,int j)(T t){}'更简洁,不会引入虚拟标识符'U'。 – 2012-07-09 23:02:26

3

“与S工作只是”并没有真正意义上d,因为 S是不是一个类型,这是一个模板

模板是本身 D中的“某些东西”,与其他语言不同。

你写了什么是一个速记

template S(int a, int b) { struct S { } } 

所以的全名是S(a, b).S,为ab无论你使用。没有办法使其“一般”参考S

如果你需要这样的约束,我建议把一些私人的东西放在S之内,并检查T是否有相同的成员。

+0

有*是*的方式一般检查S'的'情况下,看到戴维斯的答复。 – 2012-07-08 18:40:32

+1

@jA_cOp:他的回答#1与我在帖子中放置的东西完全一样(放置一个成员并检查它)。但是,#2是绝对的东西我从来没有见过o.o – Mehrdad 2012-07-08 20:01:42

+0

@Mehrdad#2之类的事情,一般只有谁真正地研究'is'表达的人了解。我最近才发现它。基本的'is'表达式足够简单,但'is'表达式可以做一个_lot_(对于一个构造来说可以说是太多了)。另外,尽管我对语言非常了解,但我越来越不愿意说你不能在D中做点什么。语言是足够灵活的,以至于有人实际上已经找到了一种办法去做一些看起来不可能的事情(尽管当然还有一些事情是不可能的)。 – 2012-07-08 21:22:48

7

我认为有在其他的答案一对夫妇的小熏鲱鱼。您可以使用模式匹配来判断T是否是S的某个实例,如下所示。

最简单的方式就是参数本身模式匹配:

void fun(int a, int b)(S!(a, b) t) { 
} 

更一般来说,你可以模式匹配的分离,模板约束内:

void fun(T)(T t) if (is(T U == S!(a, b), int a, int b)) { 
} 

在你有两种情况访问实例化参数。

+0

http://stackoverflow.com/q/11771079/554075 – Arlen 2012-08-03 04:45:12