2016-05-28 13 views
1

foreachをexのために関数体の外に置く方法はありますか?コードを生成する。コンパイル時foreach外部関数体系

私のシナリオでは、コンパイル時に特定のフィールドを生成するために必要な連想配列があります。残念ながら、私は実際にメンバーを生成するために関数本体の外にforeachを使用することはできません。

私は最初のmixinに1つのAAを与え、そのmixinは配列にAAを変換して2番目のmixinに渡し、2番目のmixinは再帰的ですそれ以上のメンバがなくなるまでそれ自身でng自身を呼び出すと同時に配列内の最初のメンバーを呼び出します。これはコードを生成するために使用できる3番目のmixinを呼び出します。

私は実際にそれが欲しいと思うほど滑らかでダイナミックではありません。誰かがより良い解決策を持っているかどうかは疑問でした。

は、ここに私の解決策

// First mixin that takes the associative array and a string for the mixin to handle the items 
mixin template StaticForEachAA(TKey,TValue, TKey[TValue] enumerator, string itemMixin) {  
    enum array = arrayAA!(TKey,TValue)(enumerator); // Converts the AA to an array of key-value pair structs 
    alias ArrayType = KeyValuePair!(TKey,TValue); 

    mixin StaticForEachArray!(ArrayType, array, itemMixin); // Calls second mixin with the array 
} 

// The second mixin that "fake loops" the array 
mixin template StaticForEachArray(T, T[] array, string itemMixin) { 
    static if (array.length) { 
     import std.string : format; 

     mixin(format("mixin %s!(T, array[0]);", itemMixin)); // Mixins the itemMixin to handle the current item 
     mixin StaticForEachArray!(T, array[1 .. $], itemMixin); // slices the array to remove the item we just handled 
    } 
} 

// The third mixin that can be used to do whatever has to be done with item 
mixin template StaticForEachItem(T, T item) { 
    import std.conv : to; 
    pragma(msg, to!string(item)); 
} 

そして、コンパイル時にAAからキーと値のペアを出力します連想

enum AA = [0 : 1, 1 : 2, 2 : 3]; 

mixin StaticForEachAA!(int, int, AA, "StaticForEachItem"); 

このため、「偽のforeach」を行うことです。

答えて

1

コンパイル時に実行される機能(CTFE)を活用することで、提供する連想配列(AA)のデータを使用してコードを生成するヘルパー関数を作成できます。

import std.string : format; 

string generateCodeForEachAA(TKey, TValue)(TValue[TKey] data, string foreachBody) 
{ 
    string result; 
    foreach(k, v ; data) 
    { 
    result ~= format(foreachBody, k, v); 
    } 

    return result; 
} 

この関数は、各AA要素と所与foreachBodyをフォーマットすることによって文字列に与えられたAAデータを回転させます。

enum Data = [ 0 : 1, 1 : 2, 2 : 3 ]; 

enum Code = generateCodeForEachAA(Data, q{ pragma(msg, "%1$s => %2$s"); }); 

pragma(msg, "Code: " ~ Code); 

mixin(Code); 

出力:構造体の内部のメンバーを生成し、これを使用し

Code: pragma(msg, "0 => 1"); pragma(msg, "1 => 2"); pragma(msg, "2 => 3"); 
0 => 1 
1 => 2 
2 => 3 

struct Foo 
{ 
    enum Members = [ "foo": 123, "bar": 42 ]; 
    mixin(generateCodeForEachAA(Members, q{ typeof(%2$s) %1$s = %2$s; })); 
} 

void main() 
{ 
    import std.stdio : writeln; 

    Foo f; 
    writeln("foo: ", f.foo); 
    writeln("bar: ", f.bar); 
} 

出力:

foo: 123 
bar: 42 
+0

返される文字列は、mixin「EDになることができますそれは面白いアプローチです、ありがとう、ありがとう君は。このソリューションでは、他のものに先立ってどのようにうまくいくのかがわかります – Bauss

+1

うれしいです。例えば、std.typecons.TupleはAAsを使わずに同様のことをしますが、その手法はまだ適用可能です。 – Manuzor

+0

それは私がこのアプローチを理解していないわけではない、私はすでに他のアプローチを使用するつもりだった場所で似たようなことをやっているが、とにかく感謝する – Bauss