On Saturday, 30 May 2015 at 15:06:16 UTC, short2cave wrote:
Yes, kind of. The template should be able to generate the
accessors using the fields of the struct passed as template
argument. But also a special accessor wich returns all the
items accessors, in a structured way:
---
struct Model
{
uint a, b;
}
template Structured(T)
{
alias Structured = ...;
}
---
allowing things like:
---
Structured!Model sm;
sm[0].a = 0;
sm[0].b = 0;
auto item = sm[0];
sm.a = 0;
sm.pushBack;
auto item = sm.back;
sm.length += 1,
---
etc.
Proof of concept:
import std.stdio, std.string, std.typetuple, std.traits,
std.container;
private auto genIndexerCode(string[] memberNames) {
enum f = `@property auto ref %s() { return
__parent.members[%s][__index]; }`;
string s = "";
foreach(i, member ; memberNames) {
s ~= format(f, member, i);
}
return s;
}
class ArrayOf(S) if (is(S == struct) && !isNested!S) {
private:
alias memberNames = FieldNameTuple!S;
alias memberTypes = FieldTypeTuple!S;
staticMap!(Array, memberTypes) members;
static struct Indexer {
private:
ArrayOf!S __parent;
size_t __index;
public:
S __get() {
S copy;
foreach(member ; memberNames) {
mixin(`copy.%s = this.%s;`.format(member,member));
}
return copy;
}
alias __get this;
void opAssign(S src) {
foreach(member ; memberNames) {
mixin(`this.%s = src.%s;`.format(member,member));
}
}
mixin(genIndexerCode([memberNames]));
}
public:
this() {}
auto opIndex(size_t i) {
return Indexer(this, i);
}
void insertBack(S s) {
foreach(i, mem ; memberNames) {
mixin(`members[%s].insertBack(s.%s);`.format(i, mem));
}
}
}
struct Test {
int x;
string y;
}
unittest {
auto aos = new ArrayOf!Test();
aos.insertBack(Test(5, "hi"));
aos[0].x = -7;
aos.insertBack(Test.init);
aos[1] = Test(11,"boo");
assert(aos[0] == Test(-7,"hi"));
assert(aos[1] == Test(11,"boo"));
}