用户定义的属性和编译时间评估,用于设置类成员变量

时间:2013-01-09 15:24:43

标签: templates attributes tuples d

我正在尝试更多地了解D的编译时间评估,并了解其模板,混合,属性等是如何工作的。我想尝试做的一件事就是找出一种优雅的方法来将类的成员标记为可序列化或可从数据库加载。在下面的示例中,我创建了一个元组,列出了在阅读或(稍后)序列化实例时要使用的成员。

我的第一个问题是,这是元组的正确使用吗?其次,如果是这样,有没有办法在编译时使用我分配给相关成员变量的用户定义属性自动生成这个元组?我已经挖掘了各种文档页面,如http://dlang.org/attribute.htmlhttp://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 个答案:

答案 0 :(得分:1)

这不是一个答案,但我通过定义自己的帮助器模板,并使用结构作为UDA(其值指示参数)来使用它们。帮助模板在这里:

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

它们在这里使用,允许覆盖JSON序列化器/反序列化器的JSON字段:

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

答案 1 :(得分:0)

我已经设法使用以下代码,并根据Cyber​​Shadow的答案提供的isValueInTuple模板提供了一些帮助。它仍然感觉有点笨重,但似乎完成了工作。如果我对模板的性质做了一些可怕的事情,评论/批评欢迎!

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