Определенные пользователем атрибуты и оценка времени компиляции для установки переменных-членов класса

Я пытаюсь узнать немного больше об оценке времени компиляции D и понять, как работают ее шаблоны, миксины, атрибуты и т. Д. Одна вещь, которую я хотел бы попробовать, - это найти элегантный способ отметить членов класса как сериализуемый или загружаемый из базы данных. В приведенном ниже примере я создал кортеж, который перечисляет, какие члены использовать при чтении или (позже) сериализации экземпляра.

Мой первый вопрос заключается в правильном использовании кортежей, поскольку он стоит ниже? А во-вторых, если да, существует ли способ генерировать этот кортеж автоматически во время компиляции с использованием пользовательских атрибутов, которые я присвоил соответствующим переменным-членам? Я прорыл различные страницы документации, такие как http://dlang.org/attribute.html и < a href = "http://dlang.org/phobos/std_traits.html" rel = "nofollow"> http://dlang.org/phobos/std_traits.html , но я не могу понять как правильно использовать их для этой цели (например, перебирать элементы класса и определять, какие переменные имеют желаемый атрибут). Я также не совсем уверен, имею ли я совершенно неправильное представление о том, как должны использоваться атрибуты. Любые предложения относительно наилучшего способа сделать это будут оценены.

enum ENCODABLE = 1;
alias string[string] Row;
template Tuple (T...) { alias T Tuple; }

class A {
    @(ENCODABLE) string name;
    @(ENCODABLE) int x;
    int* p;

    alias Tuple!("name","x") encodables;

    this(Row row) {
        foreach (var; encodables) {
            __traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]);
        }
    }
}

void main() {
    Row row = ["name":"Asdf", "x":"120"];//Simulated database row
    auto a = new A(row);
    writefln("%s,%d,%d", a.name, a.x, a.p);//Asdf,120,null
}
2
добавлено
Просмотры: 2
nl ja de

2 ответы

Это не очень важный ответ, но я использовал их, определяя свои собственные вспомогательные шаблоны и используя структуры как UDA (с их значениями, указывающими параметры). Шаблоны-помощники находятся здесь:

https://github.com/CyberShadow/ae/blob/master /utils/meta.d#L133

Они используются здесь, чтобы переопределить поле JSON для сериализатора JSON/unserializer:

https://github.com/CyberShadow/ae/blob/master /utils/json.d#L505

1
добавлено

Мне удалось заставить его работать со следующим кодом и немного помочь шаблону isValueInTuple на основе кода, представленного в ответе CyberShadow. Он все еще чувствует себя немного неуклюжим, но, похоже, выполняет эту работу. Комментарии/критика приветствуются, если я делаю что-то ужасное против характера шаблонов!

enum {
    ENCODABLE = "ENCODABLE",
};
alias string[string] Row;
template Tuple(T...) { alias T Tuple; }
template isValueInTuple(string s, T...) {
    static if (T.length == 0) {
        enum bool isValueInTuple = false;
    } else static if (T.length == 1) {
        static if (is(typeof(T[0]) == typeof(s))) {
            enum bool isValueInTuple = T[0] == s;
        } else {
            enum bool isValueInTuple = false;
        }
    } else {
        enum bool isValueInTuple = isValueInTuple!(s, T[0]) || isValueInTuple!(s, T[1..$]);
    }
}
template GenEncodables(U) {
    string GenEncodables() {
        string ret = "alias Tuple!(";
        int fn = 0;
        foreach (index, field; __traits(allMembers, U)) {
            static if (field != "Monitor") {//better way to avoid compilation errors here?
                static if (isAssignable!(typeof(mixin(U.stringof~"."~field)))) {
                    static if (isValueInTuple!(ENCODABLE, __traits(getAttributes, mixin(U.stringof~"."~field)))) {
                        if (fn++)
                            ret ~= ",";
                        ret ~= `"`~field~`"`;
                    }
                }
            }
        }
        ret ~= ") encodables;";
        return ret;
    }
}
mixin template Encodables() {
    mixin(GenEncodables!(typeof(this)));
}


class A {
    @ENCODABLE string name;
    @ENCODABLE int x;
    int *p;

    this() {}

    mixin Encodables;//must come after this() definition, apparently!

    this(Row row) {
        foreach (var; encodables) {
            pragma(msg, "Reading parameter "~var~" from row");
            __traits(getMember, this, var) = to!(typeof(__traits(getMember, this, var)))(row[var]);
        }
    }
}
0
добавлено