D / DLang: запрещение генерации кода для закрытых модулей встроенных функций

У меня есть модуль D, который, я надеюсь, содержит открытые и закрытые части. Я пытался использовать ключевые слова private и static перед определениями функций. У меня есть функция, которую я хочу сделать внешне вызываемой / публичной, и в идеале я хотел бы, чтобы она была встроена в сайт вызова. Эта функция вызывает другие внутренние функции модуля, которые предназначены быть частными, то есть не вызываемыми извне. Вызовы к ним успешно встроены в модуль, и большая часть промаха устраняется CTFE плюс распространение с известной постоянной. Однако компилятор GDC также генерирует копии этих внутренних подпрограмм, даже если они были встроены в случае необходимости и не должны вызываться извне. Я компилирую с -O3 -frelease. Что я должен делать - должен ли я ожидать этого, даже если я использую static и / или private?

Я также кратко рассмотрел эту ветку о GCC, надеясь на понимание.

Как я упоминал ранее, я пытался использовать private и static для этих внутренних функций, но я не могу подавить генерацию кода. Я мог бы понять это, если бы отладчику требовались копии этих подпрограмм для установки точек останова. Я должен подчеркнуть, что, возможно, это можно как-то решить во время соединения, насколько я знаю. Я не пробовал связывать программу, я просто смотрю на сгенерированный код в Matt Godbolt D Compiler Explorer, используя GDC. Все может быть превращено в шаблоны с помощью списка параметров шаблона нулевой длины (например, auto my_fn()(в arg_t x)), попробуйте, это не помогает, но не причиняет вреда.

Несколько других вещей, которые можно попробовать: я мог бы попытаться создать статический класс с закрытыми частями, как способ реализации пакета в стиле Ada. (Строго должен быть один экземпляр.) Я никогда не делал C++, только огромное количество asm и C профессионально. Так что это будет кривой обучения.

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

Грубый пример

module junk;

auto my_public_fn() {  return my_private_fn();  }

private
static // 'static' and/or 'private', tried both
auto my_private_fn() { xxx ; return whatever; }

1 ответ

Решение

Я только что провел короткую дискуссию с Иэйном по этому поводу, и реализовать это не так просто, как кажется.

Прежде всего static имеет много значений в D, но значение C локальной функции единицы перевода не входит в их число;-)

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

Теперь вот подвох: мы не можем точно знать, не используется ли функция:

private void fooPrivate() {}

/*template*/ void fooPublic()()
{
    fooPrivate();
}

При компиляции файла GDC ничего не знает о fooPublic шаблон (так как шаблоны могут быть полностью проанализированы только при создании экземпляра), поэтому fooPrivate кажется неиспользованным. Когда позже с помощью fooPublic в другом файле GDC будет полагаться на fooPrivate будучи уже отправленным в исходном коде - в конце концов, это не шаблон, поэтому он не отправляется в новый модуль.

Могут быть обходные пути, но вся эта проблема кажется нетривиальной. Мы могли бы также ввести обычай gcc.attribute атрибут для этого. Это вызвало бы те же проблемы с шаблонами, но поскольку это особая аннотация для одного варианта использования (в отличие от private) мы можем положиться на пользователя, чтобы поступить правильно.

Другие вопросы по тегам