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
) мы можем положиться на пользователя, чтобы поступить правильно.