Read conditional function parameters during compile time using __traits

Eugene Wissner via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Jun 21 13:13:46 PDT 2017


On Wednesday, 21 June 2017 at 19:39:14 UTC, timvol wrote:
> Hi! I've a simple array of bytes I received using sockets. What 
> I want to do is to calculate the target length of the message. 
> So, I defined a calcLength() function for each function code 
> (it's the first byte in my array). My problem is that I defined 
> the calcLength() function using conditions so that each 
> calcLength should be called depending on the respective 
> function code, see below:
>
> module example;
>
> private
> {
>     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
>     }
> }
>
> size_t doCalcLength(ubyte ubFuncCode)
> {
>     return calcLength!(ubFuncCode)();
> }
>
> int main()
> {
>     doCalcLength(1);
>     return 0;
> }
>
> 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;
> }
>
> --> During runtime:
>
> size_t doCalcLength(ubyte ubFuncCode)
> {
>     auto length = 0;
>
>     if ( ubFuncCode in calcLengthArray )
>     {
>         length = calcLengthArray[ubFuncCode]!(ubFuncCode)();
>     }
>
>     return length;
> }
>
> 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.

Let us to look at your function:

size_t calcLength(ubyte ubFuncCode)() if ( ubFuncCode == 1 )
{
     return 10; // More complex calculated value
}

This function accepts only one template parameter and no other 
parameters. Template parameter should be known at compile time. 
You can't pass a value read from socket, because you can read 
from socket only at runtime. It is what the error message says.
You calls such function as follows:

calcLength!1()
calcLength!2()
and so on.

Your doCalcLength won't work for the same reason. You try to pass 
"ubFuncCode" known at runtime as a template parameter, you will 
get the same error.
You can try to instantiate all calcLength overloads and save them 
in calcLengthArray at some index just like you already do, but 
without any template parameters. The call would look something 
like:

    length = calcLengthArray[ubFuncCode]();

But it is simplier and shorter just to use a switch statement:

switch (ubFuncCode)
{
   case 1:
     Do what calcLength!1() would do
     break;
   case 2:
     Do what calcLength!2() would do
     break;
   default:
     break;
}


More information about the Digitalmars-d-learn mailing list