Template help
Anonymous via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Jul 12 14:17:07 PDT 2014
I got to typing one day and came up with this. What it does is
search an aggregate for a member named match. If it's a direct
member, it evaluates to that. If it's not, then it searches any
aggregate type sub-members (deep members) for match. If there's
only one deep member tree with match, it evaluates to that.
Otherwise you get static assertion errors for no match or an
ambiguous match. Maybe I'm doing something completely wrong in
my code, and I certainly don't think it's pretty, but it seems to
work how I expect.
So say some variable Foo has member Bar. Bar has member Baz,
which has member Thing. Instead of writing auto x =
Foo.Bar.Baz.Thing; you can write auto x = Foo.Extract!"Thing".
The trouble comes in if there's more than one tree with Thing in
it.
Except when I want a deep member that happens to be a function. I
can't for the life of me figure out how to recurse down the
member hierarchy while carrying along the arguments, or bubble up
some alias to the function at the bottom which I then pass the
arguments.
If I get past that, I want to try and play with automatic, ad-hoc
type generation based on X functions you try to call on Y members.
template agg_mems(T) {
enum T_instance = T.init;
alias pred(string name) = isAggregateType!(totype!name);
alias totype(string name) =
typeof(__traits(getMember,T_instance,name));
alias agg_mems = Filter!(pred, __traits(allMembers,T));
}
/**
Evaluates to true if match is a member or sub-member of T, and
false otherwise.
Issues assertion failure if more than one sub-member is a match.
Used primarily by DeepMember.
*/
template hasDeepMember(T, string match) {
static if (hasMember!(T,match)) enum hasDeepMember = true;
else {
enum T_instance = T.init;
alias name_list = agg_mems!T;
//flatten our hasDeepMember to one parameter, a member name
alias test_unary(string name) =
hasDeepMember!(typeof(__traits(getMember,T_instance,name)),
match);
alias haves = Filter!(test_unary, name_list);
static assert(haves.length < 2,T.stringof~" ambiguous match for
"~match);
//if we find a match among sub-members, evals to true
static if (haves.length == 1) enum hasDeepMember = true;
else enum hasDeepMember = false;
}
}
template DeepMember(T, string match, parent...)
{
//test match
static if (hasMember!(T,match)) enum DeepMember =
TypeTuple!(parent, match);
else {
enum T_instance = T.init;
alias name_list = agg_mems!(T);
//flatten our presence test down to one parameter for Filter
alias test_unary(string name) =
hasDeepMember!(typeof(__traits(getMember,T_instance,name)),
match);
alias next = Filter!(test_unary, name_list);
static assert(next.length < 2,T.stringof~" has ambiguous match
for "~match);
static if (next.length == 1) {
//accumulate hierarchy of members
enum DeepMember = DeepMember!(
typeof(__traits(getMember,T_instance,next[0])),
match,
TypeTuple!(parent,next[0]));
}
else static assert(false,T.stringof~" has no match for "~match);
}
}
auto ref Extract(string match, T, S...)(auto ref T var, auto ref
S args) {
static if (hasMember!(T, match)) {
static if (args.length == 0) return
__traits(getMember,var,match);
else return __traits(getMember,var,match)(args);
}
else {
alias tree = DeepMember!(T, match);
static assert(tree.length > 0);
return DeepExtract!(T,tree)(var);
}
}
auto ref DeepExtract(T, tree...)(auto ref T var) {
static if (tree.length == 1) return
__traits(getMember,var,tree[0]);
else {
alias next_T = typeof(__traits(getMember,var,tree[0]));
return DeepExtract!(next_T,
tree[1..$])(__traits(getMember,var,tree[0]));
}
}
More information about the Digitalmars-d-learn
mailing list