D — Установить значение по умолчанию для элемента структуры, который является многомерным статическим массивом

#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() выглядит длинным, и я подозреваю, что мог бы быть лучший (более идиоматичный, более читаемый) способ выразить мое намерение.


Обновить еще несколькими попытками:

  1. int [SIZE] [SIZE] a = NA; не компилируется даже с текущей бета-версией: dmd-2.066-b2.

  2. int [SIZE] [SIZE] a = NA.repeat (SIZE).array (); Компилирует и выполняет то, что нужно. Тем не менее, страдает согласованность.

  3. int [SIZE] [SIZE] a = [NA, NA, NA]; похоже, что это, по сути, приведенное выше выражение, упрощенное. Он компилируется, но заполняет NA s только первый подмассив из трех элементов. Два других подмассива содержат некоторый мусор, подобный материалу. Это какая-то функция частичной инициализации? На мой взгляд, это больше похоже на ошибку, например, компилятор принимает недопустимый код.

  4. int [SIZE] [SIZE] a = [NA]; устанавливает для первого подмассива значение [-1, 0, 0] , а для остальных — тот же мусор, что и при предыдущей попытке.

  5. Также существует 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. («Точно такая же сборка» относится к дальнейшему использованию структуры, а не к инициализации.)