#multidimensional-array #initialization #d #dmd #member-initialization
#многомерный массив #инициализация #d #dmd #элемент-инициализация
Вопрос:
Я использую язык программирования D. Я хочу иметь, struct
содержащий многомерный статический массив int
s, изначально заполненный ненулевым значением (в моем случае ноль является допустимой записью, и я хочу изначально пометить все записи как недопустимые). Поскольку это struct
, у него не может быть конструктора по умолчанию. Вместо этого я могу указать значение по умолчанию для элемента struct
.
Вопрос в том, как мне записать значение этого многомерного массива коротким и читабельным способом? Существует ли какая-либо удобная функция, синтаксис особого случая или идиома для этого?
Вот что я придумал.
import std.range;
import std.stdio;
struct S
{
static immutable int SIZE = 3;
static immutable int NA = -1;
int [SIZE] [SIZE] a = NA.repeat(SIZE).array().repeat(SIZE).array();
}
void main()
{
S s;
writeln(s);
}
При этом выводится массив -1
s, как и ожидалось:
S([[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]])
Тем не менее, выражение NA.repeat(SIZE).array().repeat(SIZE).array()
выглядит длинным, и я подозреваю, что мог бы быть лучший (более идиоматичный, более читаемый) способ выразить мое намерение.
Обновить еще несколькими попытками:
-
int [SIZE] [SIZE] a = NA;
не компилируется даже с текущей бета-версией: dmd-2.066-b2. -
int [SIZE] [SIZE] a = NA.repeat (SIZE).array ();
Компилирует и выполняет то, что нужно. Тем не менее, страдает согласованность. -
int [SIZE] [SIZE] a = [NA, NA, NA];
похоже, что это, по сути, приведенное выше выражение, упрощенное. Он компилируется, но заполняетNA
s только первый подмассив из трех элементов. Два других подмассива содержат некоторый мусор, подобный материалу. Это какая-то функция частичной инициализации? На мой взгляд, это больше похоже на ошибку, например, компилятор принимает недопустимый код. -
int [SIZE] [SIZE] a = [NA];
устанавливает для первого подмассива значение[-1, 0, 0]
, а для остальных — тот же мусор, что и при предыдущей попытке. -
Также существует
fill
вstd.algorithm
, но он работает для диапазонов (не диапазонов диапазонов) и не выглядит так, как будто его легко использовать в инициализаторе. По крайней мере, оно не будет короче.
Комментарии:
1. ага, для одномерного массива вы можете просто установить его в целое число. Для многомерного статического массива мне кажется, что, возможно, должно работать то же самое, поскольку они действительно имеют одинаковую память. конечно, это усовершенствование компилятора, а не реальный ответ. tbh я бы просто взял вашу длинную строку и создал из нее функцию, чтобы она была легко читаема в точке использования, и вызвал бы ее done.
2. Если я хорошо помню, были разговоры об улучшении инициализации статического массива, чтобы разрешить что-то вроде
int[100][100] arr = 40;
. Попробуйте новый 2.066b1, возможно, он там есть.3. @Adam: вы имеете в виду рекурсивный шаблон, специализированный для элементов массива и не-массива? Это хорошая идея, но все же немного излишне для такой простой задачи, вам не кажется?
4. @DejanLekic: пробовал с 2.066b2, не работает. Смотрите обновление в вопросе.
Ответ №1:
Как насчет чего-то подобного:
module main;
import std.stdio: writeln;
enum SIZE = 3;
enum NA = -1;
struct Int {
int v = -1;
alias v this;
}
struct S
{
Int [SIZE] [SIZE] a;
}
void main()
{
S s;
writeln(s);
}
Комментарии:
1. Выглядит неплохо, спасибо! И с помощью простого теста
dmd -O -release -inline -noboundscheck
создает точно такую же сборку. Таким образом, возможности оптимизации для этойInt
структуры сравнимы с простойint
, что также может быть важно.2. («Точно такая же сборка» относится к дальнейшему использованию структуры, а не к инициализации.)