12

私が書くなら

enum chars = digits ~ uppercase;

文字列はコンパイル時に連結されますか? そうなると思います。これを文字列リテラルまたは CTFE 関数に置き換えた場合、大きなパフォーマンスの違いを測定することはできません (1 億回呼び出しても)。enum を const に置き換えると違いがあります。このように書くのは効率が悪いと言われました。便利だなと思いましたし、非効率さはわかりません。(ところで、この行は再帰的に呼び出される関数にあります)。

完全なコード (基数が異なる数値システムに変換)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}

編集:コメントに応じて更新されたコード、質問には関係ありません

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}
4

2 に答える 2

9

enumそのようなインスタンス化は常にコンパイル時に評価されます (コンパイル時に評価が不可能な場合はコンパイル エラーをスローします)。

そのため、連結はコンパイル時に行われ、不変バージョンがコードに格納され、実行時に参照されます

于 2011-07-03T13:05:47.017 に答える
5

コンパイル時に文字列が連結されているかどうかを自分で確認する1つの方法は、コードをコンパイルしてオブジェクトファイルを調べることです。あなたのファイルが呼ばれると仮定しますtest.d

dmd -c test.d
objdump test.o | grep -C3 "012345"

...次のようなものを生成する必要があります:

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......

(これはLinuxの場合です。他のプラットフォームでは、オブジェクトファイルを検査するためにさまざまなツールが必要になります。)

enumconstまたはに変更するとstring、(おそらく)出力が得られません。検索するための連結された文字列はありませgrepん。

ただし、コンパイラは、使用されていない場合でも、コンパイル時に文字列を連結する場合enumがあります。このプログラムを検討してください。

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }

次に、それをコンパイルして、オブジェクトファイルを調べます。

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........

x、、yおよびzはすべて静的リテラルであることがわかります。(マークabおよびcconst代わりにenum、との代わりに、異なる動作が表示される場合があります。)したがって、enumはコンパイル時の評価を保証しますが、enumがなくてもコンパイル時の評価が妨げられることはありません。

于 2011-07-16T17:57:21.103 に答える