2016-02-29 40 views
2

编译时是否可以将Foo转换为ubyte[size]在编译时可以将Foo转换为ubyte [size]吗?

这是一个有点背景:

struct Algebraic(Types...) 
if(Types.length < char.max - 1){ 
    import std.traits: Largest; 
    import std.meta: IndexOf; 
    static immutable maxSize = Largest!(Types).sizeof; 

    this(T)(in T t) 
    if(IndexOf!(T, Types) !is -1){ 
     type = IndexOf!(T, Types); 
     data = *cast(ubyte[maxSize]*)&t; 
    } 

    void opAssign(T)(in T t) 
    if(IndexOf!(T, Types) !is -1){ 
     type = IndexOf!(T, Types); 
     data = *cast(ubyte[maxSize]*)&t; 
    } 

    inout(T*) peek(T)() inout{ 
     if(type is IndexOf!(T, Types)){ 
      return cast(inout(T*))&data; 
     } 
     return null; 
    } 
private: 
    ubyte[maxSize] data; 
    char type = char.max; 
} 

struct Branch{ 
    int index; 
    int left; 
    int right; 
} 
struct Leaf{ 
    int index; 
} 
struct Foo{ 
    alias Node = Algebraic!(Branch, Leaf); 
    Node n = Branch(1,2,3); 
    //Error: cannot convert &const(Branch) to ubyte[12]* at compile time 
} 

的问题是,我不能在编译时投Branchubyte[maxSize]

回答

4

我不知道有任何“干净”的方法(一个会利用ABI的编译器知识),因为CTFE在防止重新解释方面非常保守。但是,如果这是一个拦截器,它可以手动建立字节数组利用的事实,结构ABI很简单:

import std.traits; 

ubyte[T.sizeof] reinterpret (T) (T x) 
    if (!hasIndirections!T) 
{ 
    typeof(return) result; 

    static if (is(T == struct)) 
    { 
     size_t offset = 0; 
     foreach (ref field; x.tupleof) 
     { 
      result[offset .. offset + field.sizeof] = reinterpret(field); 
      offset += field.sizeof; 
     } 
    } 
    else static if (is(T : ulong)) 
    { 
     for (auto i = 0; i < x.sizeof; ++i) 
      result[i] = cast(ubyte) (x >> 8*i); 
    } 
    else 
    { 
     // handle floating types, arrays etc. 
    } 

    return result; 
} 

struct S 
{ 
    int x, y; 
} 

static immutable bytes = reinterpret(S(42, 42)); 

pragma(msg, bytes); 

有这种方法的一个巨大的限制:您需要调整适当的ABI手动。像endianess的东西是微不足道的,但正确处理字段对齐可能是一个痛苦(我甚至没有试图这样做在这个片段)。