2012-06-09 19 views
7

是否可以编写单个模板函数来递增不同结构的(数字)字段?例如:D中的结构和元组模板参数

struct Color 
{ 
    ubyte a,r,g,b; 
} 

struct Point 
{ 
    double x, y; 
} 

我想是这样的:

T update(T, A)(T t, A a) 
if (is(T == struct)) 
{ 
    auto vals = t.tupleof; 
    foreach (i; 0 .. vals.length) { 
     vals[i] += a; // error: i cannot be read at compile time 
    } 
    return T(vals); // convert back to struct 
} 

我也试着写接受元组函数模板,但元组总是被扩展,从而可以防止编译器匹配正确的模板。 谢谢。

回答

12

那么,我会说你正在做的事情是相当奇怪的,但它肯定是可能的。最天真的,现场的方式很可能是:

void update(T)(ref T t) 
    if(is(T == struct)) 
{ 
    foreach(ref var; t.tupleof) 
     ++var; 
} 

与副本做,很可能会复制它,然后更新它,而不是试图构造一个新的使用更新的值(最简单的方法但我敢肯定,是可以做的太多,如果你真的想):

T update(T)(T t) 
    if(is(T == struct)) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
     ++var; 

    return copy; 
} 

主要问题就在这里,当然是,在这两个模板约束太弱。所有你需要做的是在你的结构中有不可增加的类型,并且它不起作用。要解决这个问题最简单的方法很可能会创建一个同名的模板,以测试它的你:

T update(T)(T t) 
    if(isIncrementableStruct!T) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
     ++var; 

    return copy; 
} 

template isIncrementableStruct(T) 
{ 
    enum isIncrementableStruct = is(T == struct) && 
           is(typeof({T t; foreach(var; t.tupleof) ++var;})); 
} 

如果你希望能够增加所有都是递增的字段,并独自离开了别人,你倒是可能做这样的事情:

T update(T)(T t) 
    if(is(T == struct)) 
{ 
    auto copy = t; 

    foreach(ref var; copy.tupleof) 
    { 
     static if(canIncrement!(typeof(var))) 
      ++var; 
    } 

    return copy; 
} 

template canIncrement(T) 
{ 
    enum canIncrement = is(typeof({T var; ++var;})); 
} 

在任何情况下,你出现在主要的事情已经错过了尝试循环访问tupleof直接在使用ref,这样的元素进行而更新不是让他们的副本是更新。

+1

神奇的魔法! – YGL