Проверьте, является ли псевдоним шаблоном в D 2.0

Как проверить, является ли псевдоним шаблоном в D 2.0?

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

Обновление:

Это должно работать так:

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

Для справки, что не работает:

  • Вы не можете использовать выражение вроде T!(...), потому что не знаете, что поставить вместо многоточия.

  • Вы не можете сказать &T, потому что это также не работает, если вам просто дали простое старое имя типа.


person user541686    schedule 30.03.2011    source источник
comment
Мне любопытно, для какой цели это может быть полезно. Обычно для работы с чем-то (Т) нужно иметь хоть какие-то знания, что это такое. Я полагаю, вы только изучаете язык?   -  person Michal Minich    schedule 30.03.2011
comment
вы также можете ознакомиться с соответствующей темой — Получить шаблон и параметры его создания — digitalmars.com/d/archives/digitalmars/D/learn/   -  person Michal Minich    schedule 30.03.2011
comment
@Michal: это полезно, потому что мне нужно знать, возвращает ли __traits(allMembers, T) фактический элемент, который будет существовать во время выполнения, или просто имя шаблона, которого может не существовать во время выполнения. Также спасибо за ссылку, но, к сожалению, она не ответила на вопрос.   -  person user541686    schedule 30.03.2011
comment
В следующий раз, задавая вопрос, будьте, пожалуйста, более подробными. Это поможет, когда вы ставите вопрос в контексте того, чего вы пытаетесь достичь, и включаете дополнительные ограничения, которые вы можете придумать. Очень помогает включить фрагмент кода с сайта вызова. Пример, который вы включили в вопрос, вводит в заблуждение. Спасибо.   -  person Michal Minich    schedule 30.03.2011
comment
@Michal: Хм ... что вводит в заблуждение в моем примере? Это именно то, что мне нужно, то есть, если вы на самом деле следуете ему и не меняете то, что я прошу, добавляя новые аргументы и т. д. ... ваш второй ответ был замечательным, за исключением того, что он получил несколько лазеек. :\   -  person user541686    schedule 30.03.2011
comment
Теперь используйте __traits(isTemplate, MyInstantiation).   -  person Narfanar    schedule 20.08.2016


Ответы (4)


Это проходит все, кроме двух тестов, которые я перечислил в другой ответ

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
}

2 теста, которые не прошли, например:

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

Если вы уверены, что в шаблоне не будет аргумента по умолчанию, содержащего "...!(...", я думаю, что его можно использовать безопасно.

person kennytm    schedule 30.03.2011
comment
Вау... это не очень красиво, но, кажется, работает! Я пытался посмотреть, смогу ли я найти какие-нибудь контрпримеры, и пока нет! +1 Я, вероятно, скоро соглашусь, если не увижу более красивых решений. :) (Однако аргумент по умолчанию всегда раздражает меня stringof...) - person user541686; 31.03.2011
comment
Кстати, __traits(compiles, { B x; }) можно переписать как is(B). :) - person user541686; 31.03.2011

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

это также накладывает дополнительное ограничение - это должен быть шаблон, который может быть создан с заданными аргументами.

person Michal Minich    schedule 30.03.2011
comment
Спасибо за предложение, но оно на самом деле не помогает, потому что вся причина, по которой я задал этот вопрос, заключалась в именно том, что я не знаю, какими должны быть аргументы. :( - person user541686; 30.03.2011

Этот код применяет адрес оператора «&», который не применим к шаблонам, для идентификации идентификатора шаблона.

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

вывод:

a is template: false
foo is template: true
xyz is template: true
bar is template: false
person Michal Minich    schedule 30.03.2011
comment
К сожалению, это приведет к неправильным значениям rvalue, поскольку у них также нет адресов. - person dsimcha; 30.03.2011
comment
Это также приведет к неправильному названию типа, потому что вы не можете взять адрес класса: struct S { struct T { } } pragma(msg, __traits(compiles, &S.T)); печатает false. :( - person user541686; 30.03.2011

Параметр псевдоним шаблона может принимать множество вещей: переменные, пользовательские типы, модули. , шаблоны и литералы.

Так что isTemplate должен пройти следующие тесты:

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 );
person Community    schedule 30.03.2011
comment
Да, мой список не был исчерпывающим, это было просто необходимое условие. :) (Это ответ?) - person user541686; 31.03.2011
comment
@Mehrdad: Нет, это не ответ. Просто слишком большой, чтобы поместиться в комментарий :) - person kennytm; 31.03.2011