Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
April 14, 2017 Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
I've got this code duplicated in quite some functions: --------------------- foreach (member; __traits(derivedMembers, API)) { // Guards against private members static if (__traits(compiles, __traits(getMember, API, member))) { static if (isSomeFunction!(__traits(getMember, API, member)) && !hasUDA!(__traits(getMember, API, member), IgnoreUDA) && !isSpecialFunction!member) { alias overloads = MemberFunctionsTuple!(API, member); foreach (MethodType; overloads) { // function dependent code here } } } } -------------------- What's the idiomatic way to refactor / reuse this code fragment? -- Johannes |
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | On Friday, 14 April 2017 at 08:24:00 UTC, Johannes Pfau wrote:
> I've got this code duplicated in quite some functions:
>
> ---------------------
> foreach (member; __traits(derivedMembers, API))
> {
> // Guards against private members
> static if (__traits(compiles, __traits(getMember, API, member)))
> {
> static if (isSomeFunction!(__traits(getMember, API, member))
> && !hasUDA!(__traits(getMember, API, member), IgnoreUDA)
> && !isSpecialFunction!member)
> {
> alias overloads = MemberFunctionsTuple!(API, member);
>
> foreach (MethodType; overloads)
> {
> // function dependent code here
> }
> }
> }
> }
> --------------------
>
> What's the idiomatic way to refactor / reuse this code fragment?
>
> -- Johannes
The Idiomatic way would be to wrap it inside another template.
In a year or so you won't need to worry about template overhead anymore, (if I succeed that is :) )
|
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | On Friday, 14 April 2017 at 08:24:00 UTC, Johannes Pfau wrote:
> I've got this code duplicated in quite some functions:
>
> ---------------------
> [...]1
>
> foreach (MethodType; overloads)
> {
> // function dependent code here
> }
> [...]2
> --------------------
>
> What's the idiomatic way to refactor / reuse this code fragment?
>
> -- Johannes
Your options are at least the following two (both untested, but should work):
Option 1: Template Mixins
---
mixin template Foo(alias API, Dg)
{
void foo()
{
[...]1
foreach (MethodType; overloads)
{
Dg(MethodType);
}
[...]2
}
}
mixin Foo!(API, (MethodType) {
// function dependent code here
});
foo();
---
Option 2: Code generation using CTFE
---
string genFoo(alias API, string justDoIt)
{
import std.array : appender;
auto code = appender!string;
code.put(`[...]1`);
code.put(`foreach (MethodType; overloads) {`);
code.put(justDoIt);
code put(`}`);
code.put(`[...]2`);
}
mixin(genFoo!(API, q{
// function dependent code here
})());
---
Personally, I'd consider the second approach to be idiomatic, but YMMW.
|
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Moritz Maxeiner | Am Fri, 14 Apr 2017 08:55:48 +0000
schrieb Moritz Maxeiner <moritz@ucworks.org>:
>
> mixin Foo!(API, (MethodType) {
> // function dependent code here
> });
> foo();
> ---
>
> Option 2: Code generation using CTFE
>
> ---
> string genFoo(alias API, string justDoIt)
> {
> import std.array : appender;
> auto code = appender!string;
> code.put(`[...]1`);
> code.put(`foreach (MethodType; overloads) {`);
> code.put(justDoIt);
> code put(`}`);
> code.put(`[...]2`);
> }
>
> mixin(genFoo!(API, q{
> // function dependent code here
> })());
> ---
>
> Personally, I'd consider the second approach to be idiomatic, but YMMW.
I'd prefer the first approach, simply to avoid string mixins. I think these can often get ugly ;-)
Is there some way to wrap the 'type selection'? In pseudo-code something like this:
enum FilteredOverloads(API) = ...
foreach(Overload, FilteredOverloads!API)
{
....
}
-- Johannes
|
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | On Friday, 14 April 2017 at 11:29:03 UTC, Johannes Pfau wrote: > > Is there some way to wrap the 'type selection'? In pseudo-code something like this: > > enum FilteredOverloads(API) = ... > > foreach(Overload, FilteredOverloads!API) > { > .... > } Sure, but that's a bit more complex: --- [...] // IgnoreUDA declaration [...] // isSpecialFunction declaration /// template FilteredOverloads(API) { import std.traits : hasUDA, isSomeFunction, MemberFunctionsTuple; import std.meta : staticMap; import std.typetuple : TypeTuple; enum derivedMembers = __traits(derivedMembers, API); template MemberOverloads(string member) { static if (__traits(compiles, __traits(getMember, API, member))) { static if (isSomeFunction!(__traits(getMember, API, member)) && !hasUDA!(__traits(getMember, API, member), IgnoreUDA) && !isSpecialFunction!member) { alias MemberOverloads = MemberFunctionsTuple!(API, member); } else { alias MemberOverloads = TypeTuple!(); } } else { alias MemberOverloads = TypeTuple!(); } } alias FilteredOverloads = staticMap!(MemberOverloads, derivedMembers); } //pragma(msg, FilteredOverloads!API); foreach(Overload; FilteredOverloads!API) { // function dependent code here } --- Nested templates and std.meta are your best friends if this is the solution you prefer :) |
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Moritz Maxeiner | Am Fri, 14 Apr 2017 13:41:45 +0000
schrieb Moritz Maxeiner <moritz@ucworks.org>:
> On Friday, 14 April 2017 at 11:29:03 UTC, Johannes Pfau wrote:
> >
> > Is there some way to wrap the 'type selection'? In pseudo-code something like this:
> >
> > enum FilteredOverloads(API) = ...
> >
> > foreach(Overload, FilteredOverloads!API)
> > {
> > ....
> > }
>
> Sure, but that's a bit more complex:
>
> ---
> [...] // IgnoreUDA declaration
> [...] // isSpecialFunction declaration
>
> ///
> template FilteredOverloads(API)
> {
> import std.traits : hasUDA, isSomeFunction,
> MemberFunctionsTuple;
> import std.meta : staticMap;
> import std.typetuple : TypeTuple;
>
> enum derivedMembers = __traits(derivedMembers, API);
>
> template MemberOverloads(string member)
> {
> static if (__traits(compiles, __traits(getMember, API,
> member)))
> {
> static if (isSomeFunction!(__traits(getMember, API,
> member))
> && !hasUDA!(__traits(getMember, API,
> member), IgnoreUDA)
> && !isSpecialFunction!member) {
> alias MemberOverloads =
> MemberFunctionsTuple!(API, member);
> } else {
> alias MemberOverloads = TypeTuple!();
> }
> } else {
> alias MemberOverloads = TypeTuple!();
> }
> }
>
> alias FilteredOverloads = staticMap!(MemberOverloads,
> derivedMembers);
> }
>
> //pragma(msg, FilteredOverloads!API);
> foreach(Overload; FilteredOverloads!API) {
> // function dependent code here
> }
> ---
>
> Nested templates and std.meta are your best friends if this is the solution you prefer :)
Great, thanks that's exactly the solution I wanted. Figuring this out by myself is a bit above my template skill level ;-)
-- Johannes
|
April 14, 2017 Re: Deduplicating template reflection code | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | On Friday, 14 April 2017 at 17:57:49 UTC, Johannes Pfau wrote:
> Am Fri, 14 Apr 2017 13:41:45 +0000
> schrieb Moritz Maxeiner <moritz@ucworks.org>:
>
>> [...]
>
> Great, thanks that's exactly the solution I wanted. Figuring this out by myself is a bit above my template skill level ;-)
>
>
> -- Johannes
No problem, I often enough encounter instances of <strikethrough>THE DAMNED COMPILER JUST NOT DOING WHAT I WANT</strikethrough> being frustrated with templates myself. Usually looking at phobos code helps, though.
|
Copyright © 1999-2021 by the D Language Foundation