テンプレート関数で、明示と暗示を混ぜるとき

LuaD(http://www.dsource.org/projects/luad)の最新版来た!これで勝つる!と思ったけど、ちょっと気になった部分が、今回のネタ。

要求機能:
> print!(T)(args);
と記述することで、
> 型Tのtypeid args
と出力される関数printを作れ。

 以上の機能を満たすものを、以下のように実装したとする。

version( Tango ){
    import  tango.io.Stdout;
} else {
    import  std.stdio;
}

class  A {}

void  print(T, U...)(U args)
{
    version( Tango ){
        Stdout.formatln("T = {}, args = {}", typeid(T), args);
    } else {
        writefln("T = %s, args = %s", typeid(T), args);
    }
}

void  main()
{
//  print!(A)(1,"hoge");                 //-- fig.1
    print!(A,int,typeof("hoge"))(1,"hoge");  //-- fig.2
}

 これをDMD1.0、DMD2.0の最新版でコンパイルしてみたところ、fig.1でコンパイルエラーが出る。エラーコード的には、タプル型Uが () と認識されているらしい。そこでfig.2のように、型Uをきっかり書いた場合、これは通った。うーむ。
 fig.1を何とか通すべく、以下の修正を加えてみた。

version( Tango ){
    import  tango.io.Stdout;
} else {
    import  std.stdio;
}

class  A {}

template  print(T)  //-- fig.3
{
    void  print(U...)(U args) {
        version( Tango ){
            Stdout.formatln("T = {}, args = {}", typeid(T), args);
        } else {
            writefln("T = %s, args = %s", typeid(T), args);
        }
    }
}

void  main()
{
    auto  h = "hoge";
    
    print!(A)(1,"hoge");                //-- fig.1
//  print!(A,int,typeof("hoge"))(1,"hoge");  //-- fig.2

    alias print!(A) p;             //-- fig.4
    p!(int,typeof("hoge"))(1,"hoge");
}

 修正箇所はfig.3である。明示的に指定すべき型Tをtemplate構文で外側に追い出し、暗黙指定したい型タプルUをtemplate内の関数で指定する。こうすることで、fig.1の記述を通すことが出来る。
 ただし問題はある。fig.2のように、「型タプルUを明示的に指定したいんだけど……」と思っての記述が、通らなくなってしまうことである。今回はfig.2については度外視ということなのでこれでOKとするが、もしfig.2の記述を通したいのなら、何か別の工夫が必要になるかもしれない。無理やり通したいのであれば、fig.4のような書き方もある……が、これは正直アレすぎる気もする。

 LuaDの最新版でこういった実装をしていて、添付サンプル hello.d が通らなくて困ってしまった、という話でした*1

 次のネタは、上記サンプルにあるtango.io.Stdoutと、std.stdioの出力フォーマットがあまりにも違いすぎるところを突っ込んでいこうかと画策してみる。

*1:これ以外にも、添付モジュール Object.d が存在することで、D言語側のobjectが破壊されるという、困ったエラーがある