constructing labels for static foreach inside switch inside foreach

cc cc at nevernet.com
Wed Jul 8 09:10:49 UTC 2020


On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer 
wrote:
> OK, so I have a situation where I'm foreaching over a 
> compile-time list of types. Inside the loop, I'm using a second 
> loop over a set of input.
>
> Inside that loop, I'm using a switch on the input, and inside 
> the switch, I'm foreaching over the type's members, to 
> construct a switch that can handle member names (this is for 
> serialization).
>
> If I encounter a certain name, then I want to break out of the 
> inner loop (it's a while loop)
>
> So naturally, I have to use break statements with labels like:
>
> innerloop:
> while(haveMoreData)
>    switchstmt:
>    switch(nextDataElement) {
>       static foreach(name; __traits(allMembers, T)) {
>       case name:
>          ... // handle it
>          break switchstmt;
>       }
>       case "STOP":
>          break innerloop;
>    }
>
> Seems simple enough, except that this inner portion is 
> unrolled, and if I have more than one type to run this on, I 
> already have an "innerloop" label defined.
>
> Is there a way to define a label using a mixin or something? or 
> do I have to wrap this in a function?
>
> Is there another way to approach this?
>
> -Steve

I think I ran into similar problems due to the requirement to use 
a labeled break inside static foreach.  I got around it by 
defining enums when my target was found and checking if it 
existed via __traits(compiles) to "ignore" the rest of the loop.
Sorry if I got what you're trying to accomplish wrong or this is 
too ugly:

class Foo {
	@(RPC) bar(int x, float f, string s) {
		// ...
	}
}

class Remoter(T) {
	void opDispatch(string s, SA...)(SA sargs) {
		alias A = getSymbolsByUDA!(T, RPC);
		static foreach (idx, FUNC; A) {
			static if (!__traits(compiles, FOUND) && hasUDA!(FUNC, RPC) && 
FUNCNAME!FUNC == s && SA.length == (Parameters!FUNC).length) {
				version(CheckImplicitlyConvertibleArgs) {
					static foreach (argi; 0 .. SA.length) {
						static if (!__traits(compiles, mixin(format("MISMATCH_%d", 
idx)))) {
							static if (isImplicitlyConvertible!(SA[argi], 
(Parameters!FUNC)[argi])) {
								//pragma(msg, format("implc ok: %s => %s", 
SA[argi].stringof, (Parameters!FUNC)[argi].stringof));
								// Parameter Ok
							} else {
								pragma(msg, format("RPC argument[%s] of %s is not 
implicitly convertible: %s => %s", argi, FUNCNAME!FUNC, 
SA[argi].stringof, (Parameters!FUNC)[argi].stringof));
								mixin(`enum bool `~format("MISMATCH_%d", idx)~` = true;`);
							}
						}
					}
					static if (!__traits(compiles, mixin(format("MISMATCH_%d", 
idx)))) {
						enum FOUND = idx;
						//pragma(msg, format("and we found: %s", FOUND));
					}
				} else {
					enum FOUND = idx;
				}
			}
		}
		static if (__traits(compiles, FOUND)) {
			alias FUNC = A[FOUND];

			// generate a packet to transmit that corresponds to RPC 
function call

		} else {
			static assert(0, format("No matching function found for %s%s", 
s, SA.stringof));
		}
	}
}

Remoter!foo remote;
remote.bar(4, 3.14f, "hello"); // succeeds
remote.bar("hi", 12); // static assert fail



More information about the Digitalmars-d-learn mailing list