Оценка времени компиляции
Если я пишу
enum chars = digits ~ uppercase;
будет ли строка конкатенирована во время компиляции? Я предполагаю, что так будет. Если я заменю его строковым литералом или функцией CTFE, я не могу измерить существенные различия в производительности (даже называя это сто миллионов раз). Я получаю разницу, если я заменю enum на const. Мне сказали, что это неэффективно, чтобы написать это так. Я думал, что это было удобно, и я не вижу неэффективности. (BTW, строка находится в функции, которая называется рекурсивно).
Полный код (преобразование в цифровую систему с другой базой)
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;
}
Ответы
Ответ 1
enum
такие экземпляры всегда оцениваются во время компиляции (и бросают ошибки компиляции, когда оценка невозможна во время компиляции)
поэтому конкатенация выполняется во время компиляции, и неизменяемая версия сохраняется в коде и ссылается во время выполнения
Ответ 2
Один из способов проверить, является ли строка конкатенированной во время компиляции, заключается в компиляции кода и проверке объектного файла. Предполагая, что ваш файл называется 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, на других платформах вам понадобятся различные инструменты для проверки объектного файла.)
Если вы измените свой enum
на const
или 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
- все статические литералы. (Mark a
, b
и c
как const
вместо enum
, и вы можете видеть другое поведение.) Таким образом, хотя enum
является гарантией оценки времени компиляции, отсутствие enum
не предотвращает оценку времени компиляции.