How to pass alias as template parameter?

Everlast Everlast at For.Ever
Mon Aug 27 18:16:29 UTC 2018


On Monday, 27 August 2018 at 09:50:01 UTC, Andrey wrote:
> Hello,
> This code doesn't compile:
>
> -----------------------------------------------------------------------
> import std.meta;
> import std.stdio;
>
> enum Option : string
> {
>     First = "-first" ,
>     Second = "-second",
>     Qwerty = "-qwerty"
> }
>
> void handler(Option option)(string[] args, ref ushort index)
> {
>     writeln("Case: ", args[index]);
> }
>
> void handler(string arg, ref ushort index)
> {
>     writeln("Default: ", arg, " at index ", index);
> }
>
// Multiple issues here.
    for example, you call handler but it means nothing at compile 
time(the writeln should give that away)
// You seem to think AliasSeq is a list/array when it is slightly 
different, nesting AliasSeq's do not produce a nested 
array(unfortunately, although it shouldn't be difficult to 
implement such a thing.

> alias Pair(alias key, alias value) = AliasSeq!(key, value);
> alias Pairs = AliasSeq!(Pair!(Option.First, 
> handler!(Option.First)), Pair!(Option.Second, 
> handler!(Option.Second)), handler);
>
> void parseArgs(alias sequence)(ushort index, string[] args)
> {
>     alias last = sequence[$ - 1];
>     alias pairs = sequence[0 .. $ - 2];
>
>     for(ushort i = index; i < args.length; ++i)
>     {
>         string arg = args[i];
>         switch(arg)
> 	    {
> 	        static foreach(pair; pairs)
> 	        {
> 	            case pair.key:
> 	                pair.value(args, i);
> 	                break;
> 	        }
> 	
> 	        default:
>                 last(arg, i);
>                 break;
> 	    }
>     }
> }
>
> void main()
> {
       // These are run time variables, that is, the compiler does 
not know about them at compile time, hence you cannot use them 
for compile time parameters(Template parameters)

>     ushort index = 1;
>     string[] args = ["-second", "123", "-qaz", "true", 
> "-first", "77", "value"];
       // This makes no sense, the only sense it could make is 
that you mean
       parseArgs!(Pairs(index, args));

       but index and args are runtime. If you convert them to 
compile time using enum then they can be passed, but Pairs is 
still malformed as is parseArgs.

>     parseArgs!Pairs(index, args);
> }
> -----------------------------------------------------------------------
>
> Output:
>>onlineapp.d(52): Error: template instance `parseArgs!("-first", 
>>handler, "-second", handler, handler)` does not match template 
>>declaration parseArgs(alias sequence)(ushort index, string[] 
>>args)
>
> I don't understand how to pass my "Pairs" alias into template 
> function "parseArgs".
>
> P.S. Yes, I know that exists "getopt".


None of that code really makes any sense. Do you have any idea 
what you are actually doing?


Better for you to use getopt until you learn what you are trying 
to do.


Basically the code is so malformed in the use of meta programming 
that it really does not make a lot of sense.

This is what you should do:

1. Write all your code without templates, don't think of meta 
programming!

2. Your code then will work fine with CTFE and will be optimized.

e.g., suppose you have

ushort index = 1;
string[] args = ["-second", "123", "-qaz", "true", "-first", 
"77", value"];
parseArgs(index, args);

Then by changing those types to enum the compiler will 
automatically evaluate the code at compile time for you! no meta 
programming involved(except the use of enum).

This is actually what you need to do because using arguments is a 
runtime thing... if you wrote your code to take compile time 
arguments you can only use them at compile time, defeating the 
whole purpose.

Your mind has not learned to divide the compile time meta 
programming with the runtime programming and so it looks like you 
are mixing the two, and they can never be mixed up!  Except that 
runtime can be executed at compile time using a "trick"(CTFE) 
which can make life very easy.


In fact, you always want to try to do everything as if it were 
runtime because you can almost always use it at compile time 
using CTFE. So you cover much more area than think you do.

Then, naturally, you will want to make the compile time version 
behave a little different and you will use a little meta 
programming, but naturally instead of trying to force it.

Then you will develop a better understanding of the meta side of 
programming, which is just really about making really efficient 
code by doing things at compile time that can be done there(such 
as precomputing values(which CTFE generally covers well), 
reducing code bloat by working in more generic type space(e.g., 
overloading is a form of meta programming), etc..)

One of the bad things about D is that it's error messages in meta 
code can be total gibberish, so it is not a good idea to over 
complicate things. You also cannot debug the meta code nor debug 
string mixins and so you'll end up wasting a lot of time and not 
get very far.

Basically you shouldn't be trying to force anything to be meta in 
D, It will generally naturally fall out of a problem after you 
realize you can generalize something and then you generalize the 
specific runtime code you already have.






More information about the Digitalmars-d-learn mailing list