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.