Metaprogramming work around

"Erèbe" erebe at erebe.eu
Tue Apr 17 05:04:42 PDT 2012


On Tuesday, 17 April 2012 at 10:29:56 UTC, Kenji Hara wrote:
> On Tuesday, 17 April 2012 at 08:28:45 UTC, Erèbe wrote:
>> Hi,
>>
>> I'm working on some metaprogramming code which implement a 
>> Factory and generate an enum from a list of string.
>>
>> So here my questions :
>>
>> 1) The documentation say mixin templates could take as 
>> TemplateParameterList
>> a "TemplateParameter , TemplateParameterList" but all my tried 
>> to instaciate this template failed lamentably.
>>
>> mixin template Foo(T, R...)
>> {
>>
>>   anotherTemplate!(T);
>>   Foo!(R);
>>
>> }
>>
>> mixin Foo!( string, string, string);
>>
>> Is something wrong with variadic template and mixin, do i miss 
>> something ?
>>
>>
>> 2) Below some code I writed and I wanted to know if you have 
>> some advice to improve it (Right maner to do it, TypeChecking, 
>> Safety, ...) <- variaidc arguments
>>
>>
>> The code is working is purpose is to create an enum of 
>> commands and to create a factory which returns me the command 
>> associated to a string.
>>
>> Thanks !
>>
>> ===========================Code============================================
>> import std.stdio;
>> import std.traits;
>> import std.conv;
>>
>>
>> //Use to create the enums of every commands
>> mixin template enumGenerator( T... )
>> {
>>
>>    template generate( T... )
>>    {
>>        enum string value = T[0] ~ ", " ~ generate!( T[2..$] 
>> ).value;
>>    }
>>
>>    template generate() { enum string value = "UNKNOW"; }
>>
>>
>>    //Here the creation of the enum
>>    mixin("enum Command { " ~ generate!(T).value ~ "};");
>>
>> }
>>
>> //Generate a function which return a command in regard of a 
>> string
>> mixin template factoryGenerator( T... )
>> {
>>    template generate( T... )
>>    {
>>        enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
>>                                ~ "return Command." ~ T[0] ~ ";"
>>                            ~ "else "
>>                                ~ generate!(T[2..$]).value;
>>    }
>>
>>    template generate() { enum string value = "return 
>> Command.UNKNOW;"; }
>>
>>    //The function in question
>>    auto CommandFactory( string cmd )
>>    {
>>            mixin( generate!(T).value );
>>    }
>>
>> }
>>
>>
>> mixin template IrcCommands( T... )
>> {
>>
>>   mixin enumGenerator!( T );
>>   mixin factoryGenerator!( T );
>>
>> }
>>
>>
>> void main()
>> {
>>
>>                       /*Command*/     /*String associated*/
>>   mixin IrcCommands!( "Connected",    "001",
>>                       "NicknameUsed", "433",
>>                       "Message",      "PRIVMSG",
>>                       "UserLeaved",   "PART",
>>                       "UserJoined",   "JOIN",
>>                       "UserQuit",     "QUIT"
>
>                          "UserQuit",     "QUIT",   // lack of 
> comma
>
>>                       "Ping",         "PING" );
>>
>>   writefln( to!string(CommandFactory("001")) );
>>
>>
>> }
>
> You can debug templates with adding static assertions in some 
> where, like:
>
> mixin template enumGenerator( T... )
> {
>     template generate( T... )
>     {
>         static assert(T.length%2==0 && is(typeof(T[0]) : 
> string));  // check
>         enum string value = T[0] ~ ", " ~ generate!( T[2..$] 
> ).value;
>     }
>     //[snip]
> }
>
> mixin template factoryGenerator( T... )
> {
>     template generate( T... )
>     {
>         static assert(T.length%2==0 && is(typeof(T[1]) : 
> string));  // check
>         enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
>                                 ~ "return Command." ~ T[0] ~ ";"
>                             ~ "else "
>                                 ~ generate!(T[2..$]).value;
>     }
>     //[snip]
> }
>
> Bye.
>
> Kenji Hara

Thanks for the comma !

The issue with static assert (in my case) is that the compiler 
blow you a full page of "template's instatiation error" before 
the message of your assert. Ok not even a page of the size of c++ 
template error, but that lead to your message be less noticeable.
While browsering the standard librairy I found this :

static if ( expression )
      //put your code here
else
   assert(false, "your message");

With this, the compiler print just one line, "your message". That 
pretty neat and readable enough for me :)

> Stick in the magic pragma(msg, value); in here you won't regret 
> it ;)
> Another important thing to note here is that you should really 
> reconsider using plain if/else if it's a production code not 
> some toy to learn meta programming.
> At very least try to generate switch over strings but I don't 
> think any D compiler optimizes it. (but it should in future)
> Real world options are binary search on string table or even 
> better built-in hash table.

Thanks for pragma, it's awesome !

You guessed right, this code is just for the sake of learning 
some D meta programming. But I will try with an built-in hash 
table.



There is something I still don't understand :

mixin template Foo( T... )
{
//Code here
}

mixin Foo!( "Hello", "Word" ); <---- Good

--------------------------------------------

mixin template Foo( A, T... )
{
//code here
}

mixin Foo!( "Hello", "Word" ); <--- Fail !
mixin Foo!( string, "Word" ); <---- Good
--------------------------------------------

mixin template Foo( alias A, T... )
{
//code here
}

mixin Foo!( "Hello", "world" ); <--- Good
mixin Foo!( string, "world" ); <--- Fail !

---------------------------------------------

Is there someone to enlight me about this behavior ?




More information about the Digitalmars-d-learn mailing list