2012-06-09 13 views
7

¿Es posible escribir una sola función con plantilla para incrementar los campos (numéricos) de diferentes estructuras? Por ejemplo:Parámetros de plantilla Struct y Tuple en D

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

struct Point 
{ 
    double x, y; 
} 

He intentado algo como esto:

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 
} 

También he tratado de escribir plantillas de función que aceptan tuplas, pero las tuplas siempre se expanden, lo que evita que el compilador de la concordancia de la plantilla correcta . Gracias.

Respuesta

12

Bueno, yo diría que lo que estás tratando de hacer es bastante extraño, pero ciertamente es posible. La manera más ingenua en el lugar probablemente sería:

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

La forma más sencilla de hacerlo con una copia, probablemente sería para copiarlo y luego actualizarlo en lugar de tratar de construir una nueva con valores actualizados (aunque estoy seguro de que eso se puede hacer también si usted realmente quiere):

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

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

    return copy; 
} 

el principal problema aquí, por supuesto, es que la restricción de plantilla en ambos éstos es demasiado débil. Todo lo que tienes que hacer es tener tipos no creíbles en tu estructura, y no funcionará. La forma más sencilla de arreglar eso probablemente sería crear una plantilla del mismo nombre para probarlo para usted:

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

Y si usted quiere ser capaz de incrementar todos los campos que están incrementable y dejar a los demás en paz, 'd probablemente hacer algo como:

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

En cualquier caso, lo más importante que usted parece haber perdido era tratar interactuando sobre tupleof directamente durante el uso de ref modo que los elementos se han actualizado en lugar de tener copias de ellos siendo actualizado.

+1

increíble brujería! – YGL

Cuestiones relacionadas