Variadic template parameters, refactor a long chain of static if's to 'functions'.
realhet
real_het at hotmail.com
Fri Jun 28 12:31:13 UTC 2019
On Tuesday, 11 June 2019 at 13:22:26 UTC, Adam D. Ruppe wrote:
> On Tuesday, 11 June 2019 at 09:26:56 UTC, realhet wrote:
>> static bool processId(bool captureIntId, alias r, alias a)(){
>> mixin("alias ta = typeof("~a.stringof~");");
>
> As I have been saying a lot, mixin and stringof should almost
> never be used together. You could write this a lot easier:
>...
Thank you for the long example, it helped me a lot!
The thing is now capable of:
- getting a specific type of parameter ->
args.paramByType!(string[int]).writeln;
- including wrapper structs. In that case, optionally can fall
back to the type inside the struct.
- handle and call events (structs or fallback as well)
- It is super easy now to make a function that can process a
specific set of events:
struct onClick { void delegate() val; }
...
struct onHold { void delegate() val; }
void processBtnEvents(T...)(bool click, bool state, bool chg,
T args){
if(click) args.paramCall!(onClick, true/*fallback to pure
delegate*/);
if(state) args.paramCall!onHold;
if(chg){
args.paramCall!onChange;
if(state) args.paramCall!onPress;
else args.paramCall!onRelease;
}
}
- Also I've found a way to exchange state values (for example a
bool for a CheckBox control):
- I can give it a pointer to a bool
- Or I can give a getter and 0 or more setter(s): bool
delegate(), void delegate(bool)
- Can be functionPointers too, not just delegates.
- example:
void fIncrementer(T...)(T args){
paramGetterType!T x;
args.paramGetter(x);
x = (x + 1).to!(paramGetterType!T);
args.paramSetter(x);
}
- it is letting me use enumerated types too -> I will not have
to write anything, and there will be an automatic
RadioButtonGroup on the screen, just bu mentioning that variable.
It will be awesome!
- Sorry for the lot of string processing and some mixin()s :D At
the end of the code below, I've learned a lot while being able to
write nicer code.
Thank you for your example code, I've learned a lot from it.
--------------------------------------------------------------
private{
bool is2(A, B)() { return is(immutable(A)==immutable(B)); }
bool isBool (A)(){ return is2!(A, bool ); }
bool isInt (A)(){ return is2!(A, int ) || is2!(A, uint ); }
bool isFloat (A)(){ return is2!(A, float ) || is2!(A, double); }
bool isString(A)(){ return is2!(A, string); }
bool isSimple(A)(){ return isBool!A || isInt!A || isFloat!A ||
isString!A; }
bool isGetter(A, T)(){
enum a = A.stringof, t = T.stringof;
return a.startsWith(t~" delegate()")
|| a.startsWith(t~" function()");
}
bool isSetter(A, T)(){
enum a = A.stringof, t = T.stringof;
return a.startsWith("void delegate("~t~" ")
|| a.startsWith("void function("~t~" ");
}
bool isEvent(A)(){ return isGetter!(A, void); } //event = void
getter
bool isCompatible(TDst, TSrc, bool compiles, bool
compilesDelegate)(){
return (isBool !TDst && isBool !TSrc)
|| (isInt !TDst && isInt !TSrc)
|| (isFloat !TDst && isFloat !TSrc)
|| (isString!TDst && isString!TSrc)
|| !isSimple!TDst && (compiles || compilesDelegate);
//assignment is working. This is the last priority
}
}
auto paramByType(Tp, bool fallback=false, T...)(T args){
Tp res;
enum isWrapperStruct = __traits(hasMember, Tp, "val") &&
Fields!Tp.length==1; //is it encapsulated in a wrapper struct?
-> struct{ type val; }
enum checkDuplicatedParams = q{
static assert(!__traits(compiles, duplicated_parameter),
"Duplicated parameter type: %s%s".format(Tp.stringof, fallback ?
"("~typeof(Tp.val).stringof~")" : ""));
enum duplicated_parameter = 1;
};
static foreach_reverse(idx, t; T){
//check simple types/structs
static if(isCompatible!(typeof(res), t, __traits(compiles,
res = args[idx]), __traits(compiles, res =
args[idx].toDelegate))){
static if(__traits(compiles, res = args[idx]))
res = args[idx]; else res = args[idx].toDelegate;
mixin(checkDuplicatedParams);
}else
//check fallback struct.val
static if(fallback && isWrapperStruct &&
isCompatible!(typeof(res.val), t, __traits(compiles, res.val =
args[idx]), __traits(compiles, res.val = args[idx].toDelegate))){
static if(__traits(compiles, res.val = args[idx]))
res.val = args[idx];
else res.val = args[idx].toDelegate;
mixin(checkDuplicatedParams);
}
}
static if(isWrapperStruct) return res.val;
else return res;
}
void paramCall(Tp, bool fallback=false, T...)(T args){
auto e = paramByType!(Tp, fallback)(args);
static assert(isEvent!(typeof(e)), "paramCallEvent() error: %s
is not an event.".format(Tp.stringof));
if(e !is null) e();
}
template paramGetterType(T...){
static foreach(t; T){
static if(isPointer!t){
static if(isFunctionPointer!t){
static if(Parameters!t.length==0)
alias paramGetterType = ReturnType!t; //type function()
}else{
alias paramGetterType = PointerTarget!t; //type*
}
}else static if(isDelegate!t){
static if(Parameters!t.length==0)
alias paramGetterType = ReturnType!t; //type delegate()
}
}
static assert(is(paramGetterType), "Unable to get
paramGetterType");
}
void paramGetter(Tr, T...)(T args, ref Tr res){ //duplicate
checking is in paramGetterType
static foreach_reverse(idx, t; T){
static foreach(t; T){
static if((isFunctionPointer!t || isDelegate!t) &&
Parameters!t.length==0 && !is(ReturnType!t==void) &&
__traits(compiles, res = args[idx]().to!Tr)){
res = args[idx]().to!Tr;
}else static if(isPointer!t && __traits(compiles, res =
(*args[idx]).to!Tr)){
res = (*args[idx]).to!Tr;
}
}
}
}
void paramSetter(Tr, T...)(T args, in Tr val){ //duplicates are
allowed
static foreach_reverse(idx, t; T){
static foreach(t; T){
static if((isFunctionPointer!t || isDelegate!t) &&
Parameters!t.length==1 && is(ReturnType!t==void) &&
__traits(compiles, args[idx](val.to!Tr))){
args[idx](val.to!Tr);
}else static if(isPointer!t && __traits(compiles,
*args[idx] = val.to!Tr)){
*args[idx] = val.to!Tr;
}
}
}
}
More information about the Digitalmars-d-learn
mailing list