Re: Metaprogramming work around
On Tuesday, 17 April 2012 at 12:46:28 UTC, Kenji Hara wrote: On Tuesday, 17 April 2012 at 12:04:44 UTC, Erèbe wrote: [snip] There is something I still don't understand : mixin template Foo( T... ) { //Code here } mixin Foo!( "Hello", "Word" ); < Good T is TemplateTypeParameter, and matches any kind of template arguments - types, values, and symbols. The both arguments "Hello" and "World" are values, so you can bind them with T. http://dlang.org/template.html#TemplateTupleParameter "mixin template Foo( A, T... ) { //code here } mixin Foo!( "Hello", "Word" ); <--- Fail ! mixin Foo!( string, "Word" ); < Good 'A' is TemplateTypeParameter, and it matches only types. In the first instantiation of Foo, A doesn't match with the value "hello". In the second instantiation, string is type, and T matches with it. http://dlang.org/template.html#TemplateTypeParameter mixin template Foo( alias A, T... ) { //code here } mixin Foo!( "Hello", "world" ); <--- Good mixin Foo!( string, "world" ); <--- Fail ! - 'alias A' is TemplateAliasParameter, and it matches both symbols and values. Then A matches with the value "Hello", but doesn't with the type string. (string is an aliased name of immutable(char)[], and it is built-in array type.) http://dlang.org/template.html#TemplateAliasParameter Kenji Hara Thanks a lot Kenji Hara, I have a better understanding of it now !
Re: Metaprogramming work around
On Tuesday, 17 April 2012 at 12:04:44 UTC, Erèbe wrote: [snip] There is something I still don't understand : mixin template Foo( T... ) { //Code here } mixin Foo!( "Hello", "Word" ); < Good T is TemplateTypeParameter, and matches any kind of template arguments - types, values, and symbols. The both arguments "Hello" and "World" are values, so you can bind them with T. http://dlang.org/template.html#TemplateTupleParameter "mixin template Foo( A, T... ) { //code here } mixin Foo!( "Hello", "Word" ); <--- Fail ! mixin Foo!( string, "Word" ); < Good 'A' is TemplateTypeParameter, and it matches only types. In the first instantiation of Foo, A doesn't match with the value "hello". In the second instantiation, string is type, and T matches with it. http://dlang.org/template.html#TemplateTypeParameter mixin template Foo( alias A, T... ) { //code here } mixin Foo!( "Hello", "world" ); <--- Good mixin Foo!( string, "world" ); <--- Fail ! - 'alias A' is TemplateAliasParameter, and it matches both symbols and values. Then A matches with the value "Hello", but doesn't with the type string. (string is an aliased name of immutable(char)[], and it is built-in array type.) http://dlang.org/template.html#TemplateAliasParameter Kenji Hara
Re: Metaprogramming work around
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
Re: Metaprogramming work around
On 17.04.2012 12:28, "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; 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. -- Dmitry Olshansky
Re: Metaprogramming work around
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