On Wednesday, 21 June 2017 at 20:48:52 UTC, ag0aep6g wrote:
On 06/21/2017 09:39 PM, timvol wrote:
size_t calcLength(ubyte ubFuncCode)() if ( ubFuncCode ==
1 )
{
return 10; // More complex calculated value
}
size_t calcLength(ubyte ubFuncCode)() if ( ubFuncCode ==
2 )
{
return 20; // More complex calculated value
}
size_t calcLength(ubyte ubFuncCode)() if ( ubFuncCode ==
3 )
{
return 30; // More complex calculated value
}
[...]
But... how can I execute these functions? I mean, calling
doCalcLength(1) function says "Variable ubFuncCode cannot be
read at compile time". So my idea is to create an array during
compile time using traits (e.g. __traits(allMembers)) and to
check this later during runtime. For illustration purposes
something like this:
--> During compile time:
void function()[ubyte] calcLengthArray;
auto tr = __traits(allMembers, example);
foreach ( string s; tr )
{
calcLengthArray[__trait(get<ubFuncCode>, s)] = s;
}
As far as I know, there's no way to get the ubFuncCode from the
constraints. In order to figure out which values are valid, you
have to try them all. Which is actually doable for a ubyte:
----
size_t function()[ubyte] calcLengthArray;
static this()
{
import std.meta: aliasSeqOf;
import std.range: iota;
foreach (ubFuncCode; aliasSeqOf!(iota(ubyte.max + 1)))
{
static if (is(typeof(&calcLength!ubFuncCode)))
{
calcLengthArray[ubFuncCode] =
&calcLength!ubFuncCode;
}
}
}
----
Using a static constructor instead of direct initialization,
because you can't initialize a static associative array
directly.
--> During runtime:
size_t doCalcLength(ubyte ubFuncCode)
{
auto length = 0;
if ( ubFuncCode in calcLengthArray )
{
length = calcLengthArray[ubFuncCode]!(ubFuncCode)();
}
return length;
}
If you can accept hard-coding the range of ubFuncCode values
here (and if there are no holes), then you can generate a
switch that calls the correct calcLength version:
----
import std.meta: aliasSeqOf;
import std.range: iota;
enum min = 1;
enum max = 3;
sw: switch (ubFuncCode)
{
foreach (code; aliasSeqOf!(iota(min, max + 1)))
{
case code:
length = calcLength!code();
break sw;
}
default: throw new Exception("unexpected ubFuncCode");
}
----
Instead of hard-coding the range, you could also do the same
here as above when filling calcLengthArray: loop over all ubyte
values and figure out which ones are valid with a `static if`.
I hope everyone knows what I want to do :). But... does anyone
know how I can realize that? I don't want to use a switch/case
structure because the calcLength() functions can be very
complex and I've over 40 different function codes. So, I think
the best approach is to use something similar to the one I
described.
I don't see how you're reducing the complexity here. You have
the same code, just spread over 40 functions, plus the extra
code to make it work. From what I see, I'd prefer the
hand-written switch.
Thanks in advance! I finally solved my problem by adjust my
message structure. So I'm now sending the length of the message,
followed by the function code and the data.
I finally created different functions and annotated them with
@FunctionCode(1), e.g.:
@FunctionCode(1)
void func1() { ... }
@FunctionCode(2)
void func2() { ... }
But I now ran into the next problem.
I'm creating an array containing these function using traits:
#1: foreach ( cb; __traits(allMembers, test))
#2: {
#3: static if ( __traits(isStaticFunction,
__traits(getMember, test, cb)) )
#4: {
#5: // do something
#6: }
#7: }
But I'm getting the following error on line #3: error: undefined
identifier '_D11TypeInfo_ya6__initZ'
I figured out that some other users are also had this error.
Unfortunately, the error wasn't solved perfectly as far as I
know. So, how can I resolve the eror?