是否可以在编译时将 Foo 转换为 ubyte[size]?
Is it possible to cast Foo to ubyte[size] at compile time?
是否可以在编译时将 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
}
问题是我无法在编译时将 Branch
转换为 ubyte[maxSize]
。
我不知道有任何 "clean" 方法(会利用 ABI 的编译器知识的方法),因为 CTFE 在防止重新解释方面非常保守。但是,如果这是一个障碍,可以利用 struct 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。诸如字节顺序之类的东西微不足道,但正确处理字段对齐可能会很痛苦(我什至没有尝试在这个片段中这样做)。
是否可以在编译时将 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
}
问题是我无法在编译时将 Branch
转换为 ubyte[maxSize]
。
我不知道有任何 "clean" 方法(会利用 ABI 的编译器知识的方法),因为 CTFE 在防止重新解释方面非常保守。但是,如果这是一个障碍,可以利用 struct 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。诸如字节顺序之类的东西微不足道,但正确处理字段对齐可能会很痛苦(我什至没有尝试在这个片段中这样做)。