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