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 ?