FunctionalFunction続き

(今日はあまり分からないまま書いてるので全体的に意味不明です。)


どうやらalias引数には、なんと関数リテラルが(!)(…)渡せてしまうようです。

Functional!((int x, int y){ return x + y; }) func;

できるわけないと思ってたのでびっくりです。これで一々普通に関数書かずにすみますね。
ところがどっこい世の中そう甘くは無いのだった。

func(3, 4); // 通る
auto f = func(2); // error!

エラーの内容はこんな感じです。

functional.d(22): Error: cannot implicitly convert expression (new foo((_param_0))) of type functional.Functional!(__dgliteral1).Functional.f!(int).f.Functional!(__dgliteral1,1u).Functional to functional.Functional!(__dgliteral1).Functional.f!(int).Functional!(__dgliteral1,1u).Functional

非常に長いので読みづらいです。ただつまり、結局は「型が違うよ!」ということです。
そんなわけない同じじゃないか、となるわけですが…関数宣言の方の型は、関数の外で宣言されているため、関数の中のnewの型に指定されている型とは名前空間の関係で微妙に違うという実に訳の分からないことになっています。
というか、それがダメなら何で今までこけてないの!という気がとてもします。
ちなみに微妙に違うといえば確かに違うものの、fは関数テンプレートなのでf!(int).fもf!(int)も同じな気もとてもします。
仕方がないので、テンプレートfの中かつ関数fの外で予め「alias Functional!(func, T.length) F;」とかしておいて型をあわせてやったとしても、今度はtraits.dの43行目のstatic assertでこけるという実に愉快なことになります。しかも関数リテラルを使ってない場合でもこけるようになるのが悲しいです。

template ReturnType(alias dg){
    alias ReturnType!(typeof(dg)) ReturnType;
}

template ReturnType(dg){
    static if (is(dg R == return))
        alias R ReturnType;
    else
        static assert(0, "argument has no return type"); // ここでこける
}

仕方が無いので元のコードに戻してうんうん唸ります。
しばらくしてから、ふと関数リテラルにキーワードと返値を書いてみました。

Functional!(function int (int x, int y){ return x + y; }) func;
func(3, 4); // 通る
auto f = func(2); // 通る!

通ってしまった…!
キーワードを省略した場合は、関数リテラルdelegateになります。どうやらdelegateが悪さをしていたようです。そして同様に、非staticなネストした関数を渡しても同じエラーが出ます。まあ似たような物らしいので当然です。
というわけで物凄く面倒臭いですが、無名delegate渡しても動くような物が書けそうに無いので、無名関数を渡す時は必ずfunctionをつけて下さい。
というか、そんなことする人あんまりいない気もしますし、ネタなのであまり気にしないことにします。寧ろ謎エラーのほうがずうっと気になるのでした。