2011-03-30 16 views
6

¿Cómo puedo comprobar si un alias es una plantilla en D 2.0?Pruebe si un alias es una plantilla en D 2.0

template isTemplate(alias T) 
{ 
    enum bool isTemplate = ???; 
} 

Actualización:

Debería funcionar como:

struct S(T) 
{ 
    int opCall() { return 0; } 
    int opUnary(string s)() if (s == "-") { return 0; } 
} 

pragma(msg, isTemplate!(S));     //Should print true 
pragma(msg, isTemplate!(S!(int)));   //Should print false 
pragma(msg, isTemplate!((S!(int)).opCall)); //Should print false 
pragma(msg, isTemplate!((S!(int)).opUnary)); //Should print true 

Como referencia, las cosas que No trabajo:

  • No puede usar ninguna expresión como T!(...) porque no sabe qué colocar en lugar de las elipsis.

  • No se puede decir &T porque eso tampoco funciona si solo le dan un nombre de tipo antiguo.

+0

Estoy courious para qué propósito esto puede ser útil. Usualmente para trabajar con algo (T) necesitas tener al menos un poco de conocimiento de lo que es. ¿Supongo que solo estás explorando el idioma? –

+0

también puede consultar el tema relacionado - Obtenga la plantilla y sus parámetros de creación de instancias - http://www.digitalmars.com/d/archives/digitalmars/D/learn/Get_template_and_its_instantiation_parameters_17854.html –

+0

@Michal: es útil porque necesito para saber si '__traits (allMembers, T)' devuelve un miembro real que existirá en tiempo de ejecución, o simplemente un nombre de plantilla que puede no existir en tiempo de ejecución. Gracias por el enlace también, pero desafortunadamente no respondió la pregunta. – Mehrdad

Respuesta

5

Esto pasa todos menos 2 pruebas que he enumerado en the other answer

import std.algorithm : startsWith, canFind; 

template isTemplate(alias B) { 
    enum isTemplate = !__traits(compiles, {auto x=B;})  // excludes values 
        && !__traits(compiles, {B x;})   // excludes types 
        && __traits(compiles, {alias B x;})  // excludes instance members 
        && !B.stringof.startsWith("module ", "package ") // excludes modules 
        && !B.stringof.canFind("!(");    // excludes instantiated templates 
} 

Las 2 pruebas que han fracasado como:

struct Inner2(string U="!(") {} 
static assert(isTemplate(Inner2)); 

Si está seguro de que la plantilla no tendrá un argumento predeterminado que contenga "...!(...", creo que es seguro de usar.

+0

Guau ... no es terriblemente bonito, pero parece funcionar. He estado tratando de ver si puedo encontrar contraejemplos , y hasta ahora, ¡no! +1 Probablemente lo acepte pronto si no veo soluciones más bonitas. :) (El argumento predeterminado siempre me fastidia con 'stringof', aunque ...) – Mehrdad

+0

Por cierto, puedes reescribir '__traits (compila, {B x;}) 'as' es (B) '. :) – Mehrdad

1
template isTemplate(alias T, Args...) 
{ 
    enum bool isTemplate = __traits(compiles, T!(Args)); 
} 

esto también pone restricción adicional - debe ser la plantilla que se pueden crear instancias con argumentos dados.

+0

Gracias por la sugerencia, pero realmente no ayuda, porque la razón por la que hice esta pregunta fue ** precisamente ** que hago * no * saber cuáles deben ser los argumentos. :( – Mehrdad

1

Este código aplica la dirección del operador-de '&' que no se aplica a las plantillas, para identificar el identificador de la plantilla.

struct S (T) { 
    int a; 
    int foo()() {} 
    int xyz (A) (A a) {} 
    void bar (T t) {} 
} 

void main() { 
    S!(int) s; 
    foreach (m; __traits(allMembers, S!(int))) 
     writeln (m, " is template: ", !__traits(compiles, mixin("&s." ~ m))); 
} 

salida es:

a is template: false 
foo is template: true 
xyz is template: true 
bar is template: false 
+5

Desafortunadamente esto obtendrá valores incorrectos, ya que tampoco tienen direcciones. – dsimcha

+1

Esto también obtendrá el nombre de un tipo incorrecto, porque no puede tomar la dirección de una clase: 'struct S {struct T { }} pragma (msg, __traits (compila, &S.T)); 'prints' false'. :( – Mehrdad

1

Un template alias parameter puede aceptar muchas cosas: las variables, tipos personalizados, módulos, plantillas y literales.

Para que isTemplate deben pasar los siguientes casos de prueba:

struct FooS(T) { 
    struct Inner {} 
    struct Inner2(string U="!(") {} 
    int func(U)() { return 0; } 
    int bar; 
} 
FooS!int foo; 

class FooC { int x; } 
union FooU { int x;} 
enum FooE { x } 
interface FooI { int x(); } 

template FooT(T) { 
    struct Inner {} 
    struct Inner2(string U="!(") {} 
    int func(U)() { return 0; } 
    int bar; 
} 

static assert(! isTemplate!0); 
static assert(! isTemplate!"0"); 
static assert(! isTemplate!0.0f); 
static assert(! isTemplate!'0'); 
static assert(! isTemplate!'!'); 
static assert(! isTemplate!"module std.stdio"); 
static assert(! isTemplate!null); 
static assert(! isTemplate!true); 
static assert(! isTemplate!__FILE__); 
static assert(! isTemplate!__LINE__); 
static assert(! isTemplate!([])); 
static assert( isTemplate!FooS); 
static assert(! isTemplate!(FooS!int)); 
static assert( isTemplate!(FooS!int.func)); 
static assert(! isTemplate!(FooS!int.func!float)); 
static assert(! isTemplate!(FooS!int.bar)); 
static assert(! isTemplate!(FooS!int.Inner)); 
static assert( isTemplate!(FooS!int.Inner2)); 
static assert(! isTemplate!(FooS!int.Inner2!"?")); 
static assert( isTemplate!FooT); 
static assert(! isTemplate!(FooT!int)); 
static assert( isTemplate!(FooT!int.func)); 
static assert(! isTemplate!(FooT!int.func!float)); 
static assert(! isTemplate!(FooT!int.bar)); 
static assert(! isTemplate!(FooT!int.Inner)); 
static assert( isTemplate!(FooT!int.Inner2)); 
static assert(! isTemplate!(FooT!int.Inner2!"?")); 
static assert(! isTemplate!foo); 
static assert( isTemplate!(foo.func)); 
static assert( isTemplate!isTemplate); 
static assert(! isTemplate!(isTemplate!isTemplate)); 
static assert(! isTemplate!FooC); 
static assert(! isTemplate!FooU); 
static assert(! isTemplate!FooE); 
static assert(! isTemplate!FooI); 
static assert(! isTemplate!((int x){return x;})); 
static assert( isTemplate!(std.stdio.writefln)); 
static assert(! isTemplate!(std.stdio)); 
static assert(! isTemplate!std); 
+0

Sí, mi lista no tenía por qué ser exhaustiva, solo era una condición necesaria :) :) (¿Es esto una respuesta? ?) – Mehrdad

+0

@Mehrdad: No, no es una respuesta. Simplemente demasiado grande para encajar en un comentario :) – kennytm

Cuestiones relacionadas