У меня есть функция, поведение которой может потребоваться изменить в зависимости от файла, из которого она вызывается (например, для увеличения вывода трассировки отладки). Эту модификацию необходимо выполнить без перекомпиляции (например, путем редактирования файла конфигурации или изменения переменной среды).
В качестве примера, который бы удовлетворял эту потребность, я мог бы написать Function()
как:
FunctionModifiable( const char* pszFile, int i );
Затем создайте макрос таким образом:
#define Function( i ) FunctionModifiable( __FILE__, (i) )
И FunctionModifiable()
будет обязан проверять pszFile
, скажем, unordered_set<>
, который был заполнен во время инициализации, чтобы увидеть, является ли специальным функциональность должна быть активирована.
Однако издержки этого поиска - минус (это высокопроизводительное программное обеспечение, и функция вызывается огромное количество раз), и есть некоторые данные для каждого файла, которые могли бы нужно кэшировать в этой ситуации. Мы можем исключить поиск и получить хранилище для кэшированной информации, передав не __FILE__
, а указатель на вспомогательный объект. Этому объекту нужно имя файла, чтобы при однократной инициализации он мог обращаться к переменным конфигурации или окружения или узнать, требуется ли ему специальная обработка.
FunctionHelperObject fho( __FILE__ );
#define Function( i ) FunctionModifiable( &fho, (i) ) // C-style solution
#define Function( i ) fho.MethodModifiable( (i) ) // C++-style solution
ОК, теперь скажите, что я хочу чтобы пользователи не могли определить это fho
в каждом файле. (В частности, мы не можем переписать все существующие файлы с вызовом Function (), хотя и говорим, что готовы их перекомпилировать).
У меня была необычная идея поместить определение переменной в заголовочный файл , так что любая программа, включающая заголовок для Function()
, получит FunctionHelperObject fho( __FILE__ )
бесплатно. (Такое определение будет #pragma once
или защищено переменной препроцессора.
Проблема заключается в том, что __FILE__
в этой точке будет именем заголовка, а не модуля компиляции верхнего уровня. Если есть был символом __CFILE__
, это было бы решением, но это не так.
В конечном счете, лучшее, что я могу придумать, имеет недостатки: 1) аспект «модифицируемый» будет доступен только в исходном коде, явно написанном для используйте его, и 2) вам придется сделать это явное написание, и 3) начать становиться немного сложнее. В коде вы хотите добавить возможность изменять поведение, чтобы вы написали USE_MODIFIABLE_FUNCTION
где-нибудь после включения соответствующего заголовка. Это был бы макрос, который создает FunctionHelperObject
выше, на этот раз в правильном «файле», поэтому __FILE__
будет иметь требуемое значение, и, кроме того, определяет макрос, как показано выше, который будет маскировать ненастраиваемую функцию Function()
с одним из двух макросов, показанных выше. Вкратце: предыдущий пример, плюс
#define USE_MODIFIABLE_FUNCTION FunctionHelperObject fho( __FILE__ );\n#define Function( i ) fho.MethodModifiable( (i) )
Код, написанный без USE_MODIFIABLE_FUNCTION
, просто назвал бы ненастраиваемый Function()
нормальным способом.
Но, безусловно, это другой принятый, переносимый способ обеспечить такое поведение? Хотя я говорил исключительно о препроцессоре C, есть ли какой-нибудь шаблон C ++ magi c или какой-либо другой подход, который будет работать?