Read conditional function parameters during compile time using __traits
timvol via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Fri Jun 23 12:08:03 PDT 2017
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?
More information about the Digitalmars-d-learn
mailing list