从模板中的struct字段中提取类型和偏移量

MaK*_*aKo 5 d

注意:即使我的例子来自OpenGL,这不是一个OpenGL问题,而是一般的D问题.

背景:在我的游戏项目中,我有一个着色器类来帮助连接到GLSL代码.制服工作很好:

uniform(string name, float value) --> glUniform1f(...)
uniform(string name, mat4 m) --> glUniformMatrix4fv( ...)
etc. etc.
Run Code Online (Sandbox Code Playgroud)

也就是说,它根据参数的类型选择正确的函数,因此当我修改我的代码时,它会自动更改为使用正确的函数(假设我没有D和GLSL之间的类型冲突).

我的麻烦是实现一些绑定属性的类似机制.我有VERTEX结构:

struct VERTEX { ...; vec3 pos; ... }
Run Code Online (Sandbox Code Playgroud)

对于绑定属性,除了知道字段的类型外,我还需要偏移量,但我不需要这些值.我设法写了一个丛生的实现,其中调用如下:

vbo.attrib!(typeof(mesh.VERTEX.pos))("vert_pos", mesh.VERTEX.pos.offsetof);
Run Code Online (Sandbox Code Playgroud)

VBO.attrib实现如下:

void attrib(T: vec2)(string name, ulong offset) { /* 2 floats from offset */ }
void attrib(T: vec3)(string name, ulong offset) { /* 3 floats from offset */ }
Run Code Online (Sandbox Code Playgroud)

问题:有没有办法让这更简单,更优雅?一般来说,我不喜欢在调用时复制字段,也就是首先提取类型来选择正确的attrib绑定函数,然后分别发送offset.我希望函数调用看起来像这样:

vbo.attrib("vert_pos", mesh.VERTEX.pos);
Run Code Online (Sandbox Code Playgroud)

...以及从参数中提取类型和偏移量的模板.我已经阅读了D模板指南和教程,但我还没弄清楚如何实现这样的模板.有可能吗?怎么样?

澄清:我有一种感觉,我已经接近,我只是没有足够的想象力(以及来自D模板和mixins的知识)来实现第一阶段:

XXX(name, field)
--> some unknown magic
--> vbo.attrib!(typeof(field))(name,field.offsetof)
--> void attrib(T: vec2)(string name, ulong offset) { /* arguments for GL call */ }
Run Code Online (Sandbox Code Playgroud)

编辑:使用mixins,我设法让它看起来像这样:

    template attrib(string name, string field)
    {
        const char[] attrib =
            "vbo.attrib!" ~
            "(typeof(" ~ field ~ "))" ~
            "(\"" ~ name ~ "\", " ~ field ~ ".offsetof);";
    }

    mixin(attrib!("vert_pos", "mesh.VERTEX.pos"));
    mixin(attrib!("vert_uv", "mesh.VERTEX.uv"));
Run Code Online (Sandbox Code Playgroud)

说实话,它(调用)看起来比我现在使用起来更复杂,所以我保持现状并寻找更好看的解决方案.

use*_*958 5

你真的非常接近解决方案.这适用于DMD git head:

import std.stdio;

struct vec2 {
  float a, b;
}

struct vec3 {
  float a, b, c;
}

struct VERTEX {
  vec3 pos;
  vec2 uv;
}

void attrib(T: vec2) (string name, ulong offset) {
  writefln("vec2: name=%s; ofs=%s", name, offset);
}

void attrib(T: vec3) (string name, ulong offset) {
  writefln("vec3: name=%s; ofs=%s", name, offset);
}


static void attrib(string name, alias field) () {
  attrib!(typeof(field))(name, field.offsetof);
}


void main () {
  attrib!("vert_pos", VERTEX.pos); // outputs "vec3: name=vert_pos; ofs=0"
  attrib!("vert_uv", VERTEX.uv); // outputs: "vec2: name=vert_uv; ofs=12"
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我没有正式的2.066版本来检查它是否适用它.这肯定不适用于2.065,所以你对GDC运气不好(因为它仍然使用2.065).

诀窍是static,这意味着"这个模板不需要任何上下文".

ps刚检查过,是的,这适用于2.066版本.