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

Reply via email to