Подтвердить что ты не робот

D шаблоны: самый крутой взлом

Какой самый классный несколько практичный метапрограммирующий взлом, который вы сделали или видели на языке программирования D? Несколько практических средств, исключающих, например, raytracer для компиляции.

4b9b3361

Ответ 1

В терминах самого крутого, я должен был бы сказать Kirk McDonald PyD (и другие аналогичные привязки), поскольку они выполняют огромную работу по обнаружению и обработке множества разных типов, а также к сложной генерации кода.

Тем не менее, PyD выигрывает только потому, что BLADE технически использует CTFE, а не шаблоны.

В более личном примечании, D-шаблоны широко используются в моем исследовательском проекте. Это симуляционная структура, в которой модули могут определять свои собственные частные типы данных. Для отображения нового типа пользователя в фреймворке требуется одна строка кода, которая создает синтаксический анализатор XML для этого типа, а также соответствующий код сериализации/десериализации сети.

Ответ 3

Инструменты DParse в Scrapple - это шаблонный генератор парсера. Тем не менее, ldc является единственным компилятором D с функциональным временем компиляции GC (но даже тогда он имеет несколько случайных случайных сбоев). Я немного поиграл с ним, и вы можете сделать некоторые интересные вещи, такие как синтаксический анализ конфигурационных файлов и прочее, но до тех пор, пока GC GC компиляции не будет полностью запущен, вы не сможете делать большие вещи.

Ответ 4

D/ Objective-C Bridge использует шаблоны, чтобы вы могли манипулировать объектами Cocoa в D.

Ответ 5

Моими фаворитами будут ElemType и KeyType из tools.base:

template ElemType(T) {
  alias typeof((function() {
    foreach (elem; Init!(T)) return elem; assert(false);
  })()) ElemType;
}

template KeyType(T) {
  alias typeof((function() {
    foreach (key, elem; Init!(T)) return key; assert(false);
  })()) KeyType;
}

Ответ 6

Компиляция хэширования строки времени. Вы можете использовать это для обфускации встроенных строк в свой код. Просто найдите "хэш". довольно много других интересных образцов на этой странице.

Ответ 8

Одним из примеров является bitfields в стандартной библиотеке D, которая генерирует код для манипуляции с полем бит, начиная с пользовательского макета.

объект Tuple - еще один пример. Он генерирует кортеж на основе пользовательских типов и дополнительных имен. Существует не так много генеративных umph там, кроме как для ввода именованных полей, но я считаю это иллюстративным примером.

Не зная о эксплойте Ламберта, я просто добавил memoize в стандартную библиотеку - см. здесь для документации, здесь для кода и здесь для соответствующего обсуждения в группе новостей.

Другим объектом, над которым я работал, является функция более высокого порядка, которая отображает интегральную или вещественнозначную функцию (например, предлагает быструю экспоненту). Это еще не готово к выпуску.

Как только создание объекта будет разрешено во время компиляции, его будет легко создать, например. двигатели регулярных выражений, которые генерируют все автоматы во время компиляции.

Ответ 9

Я отвечу на свой вопрос, потому что этого не было, когда я спросил его. Я написал патч сборщику мусора, который использует шаблоны и интроспекцию времени компиляции, чтобы генерировать информацию смещения указателя для произвольно сложных пользовательских типов, чтобы обеспечить точное сканирование кучи вместо того, чтобы это было сделано внутри компилятора.

Ответ 10

Я написал функцию memoize(), чей заголовок это (код немного длинный для вставки здесь):

auto memoize (TFunc) (TFunc func);

Что он делает, вы даете ему адрес функции, и он возвращает строго типизированный делегат (тот же тип сигнатуры и возвращаемого типа, что и исходная функция), который кэширует возвращаемые значения исходной функции, так что вызов ее дважды с один и тот же параметр только один раз вызывает базовую функцию. Например, это мемуаризованное "рекурсивное" определение последовательности Фибоначчи, которое выполняется в линейном, а не экспоненциальном времени:

uint fib (uint n) {return n > 0? n > 1? memoize (& fib) (n - 1) + memoize (& fib) (n - 2): 1: 0; }

Вы можете назвать это нормально, как в: fib (1000);


Изменить: предыдущий код, ссылка которого я разместил, была довольно отвратительной; эта версия намного более элегантна.

Ответ 11

Миксины для чтения и записи простых структур из объекта Stream:

template TStructReader() {
        private alias typeof(*this) T;
        static T opCall(Stream stream) {
                assert(stream.readable);
                T ret; stream.readExact(&ret, T.sizeof);
                return ret;
        }
}

template TStructWriter() {
        private alias typeof(*this) T;
        void write(Stream stream) {
                assert(stream.writeable);
                stream.writeExact(this, T.sizeof);
        }
}

Используйте его следующим образом:

align (1) struct MyStruct {
        ... definitions here ...
        mixin TStructReader;
        mixin TStructWriter;
}

auto ms = MyStruct(stream);
ms.write(stream);

Ответ 12

LuaD также широко использует метапрограммирование для бесшовного взаимодействия с Lua. Вы можете зарегистрировать весь класс с помощью одной команды.