#c #macros #c-preprocessor #static-methods
#c #макросы #c-препроцессор #статические методы
Вопрос:
Я пытаюсь написать программное обеспечение, которое может вести себя по-разному в зависимости от того, должен ли определенный компонент моделироваться в программном обеспечении или выполняться на реальном оборудовании. Однако GCC жалуется, что оператор разрешения области видимости (::) не может быть использован в макросе, поэтому мой вопрос: возможно ли определить макрос для вызова статического метода?
Моя цель — иметь возможность, используя другое определение препроцессора, выбирать между использованием всех реальных компонентов (0), использованием всех моделируемых компонентов (1) или использованием сочетания реальных и моделируемых компонентов (2). В этом последнем случае я сталкиваюсь с этой проблемой. При этом условии я хочу вызвать функцию, которую я «защищаю», реализуя ее как статический метод. Вот мой подход:
#define SIM_CONF 2
#if SIM_CONF == 0
#define IS_HW_SIMULATED(name) false
#define IS_HW_REAL(name) true
#endif
#if SIM_CONF == 1
#define IS_HW_SIMULATED(name) true
#define IS_HW_REAL(name) false
#endif
#if SIM_CONF == 2
#define IS_HW_SIMULATED(name) SimConfig::isSimulated(name)
#define IS_HW_REAL(name) SimConfig::isReal(name)
#endif
class SimConfig
{
public:
static bool isSimulated(const char* szName);
static bool isReal(const char* szName);
};
РЕДАКТИРОВАТЬ: вот пример того, как я использую его в другом месте:
void PumpComponent::commandRevs(float revs)
{
#if IS_HW_SIMULATED("PumpComponent")
// do simulation procedure
#else
// do real hardware procedure
#endif
}
Когда я компилирую, GNU Make жалуется:
error: token "::" is not valid in preprocessor expressions #define IS_HW_SIMULATED(name) SimConfig::isSimulated(name)
Есть ли какой-то подход, при котором я могу защитить / инкапсулировать функции isSimulated()
and и isReal()
при этом иметь возможность ссылаться на них в директивах препроцессора?
Комментарии:
1. Использование макросов для таких вещей обычно не одобряется, в частности, в C . Почти всегда есть лучшие способы сделать то, чего вы пытаетесь достичь, без использования макросов.
2. Здесь все работает нормально. какую версию вы используете?
3. … и как вы вызываете компилятор для этого файла?
4. Я понимаю это и определенно предпочел бы избегать макросов, к сожалению, кодовая база, над которой я работаю, уже сильно зависит от них. Мне интересно, есть ли способ, которым я могу работать в этих пределах без полного рефакторинга остальной части программного обеспечения.
5. Это было бы недопустимо, поскольку оператор разрешения области (::) не может использоваться в макросе.
Ответ №1:
Проблема в том, как вы используете этот макрос. Вы поместили его в качестве #if
аргумента препроцессора.
Процессор не понимает код, и аргумент #if
должен быть чем-то, что процессор может обрабатывать, поэтому макросы и литералы.
SimConfig::isSimulated
это код, который еще не определен. Это будет известно во время процесса компиляции, поэтому после завершения предварительной обработки.
Один из способов исправить это — просто использовать if
else
void PumpComponent::commandRevs(float revs)
{
if IS_HW_SIMULATED("PumpComponent") {
// do simulation procedure
} else {
// do real hardware procedure
}
}
Это не проблема для компилятора. будет замечено, что это постоянное значение и должно удалить устаревший код.
Другой способ исправить это — отказаться от макросов. Вы можете использовать шаблоны.
Или вложите материал, зависящий от макросов, в некоторый класс и используйте макросы для изменения функциональности этого класса (таким образом, эти макросы не будут распространяться по всему вашему коду).
Комментарии:
1. «Вы можете использовать шаблоны». Что еще более важно, вы можете использовать
constexpr
and thenif constexpr
. Затем компилятор долженfalse
использовать регистр.2. Переключение класса на шаблонный класс устранило проблему для меня. Спасибо!
Ответ №2:
Не используйте #if
для этого. Просто напишите обычный код:
void PumpComponent::commandRevs(float revs)
{
if (IS_HW_SIMULATED("PumpComponent")) {
// do simulation procedure
} else {
// do real hardware procedure
}
}
Компилятор удалит одну из ветвей, если SIM_CONF
значение равно 0 или 1, поскольку условие ветвления является константой времени компиляции. Он сохранит ветви, когда будет 2.
Тем не менее, я не вижу причин для IS_HW_SIMULATED
IS_HW_REAL
использования макросов and вообще. Глядя на опубликованный вами код, кажется, вам нужна только одна функция: SimConfig::isSimulated()
:
bool SimConfig::isSimulated(const char* szName)
{
#if SIM_CONF == 1
(void)szName; // supress "unused parameter" warning
return true;
#else
// Your normal implementation.
#endif
}
Тогда остальной части вашего кода не нужно использовать какие-либо макросы:
void PumpComponent::commandRevs(float revs)
{
if (SimConfig::isSimulated("PumpComponent")) {
// do simulation procedure
} else {
// do real hardware procedure
}
}
SimConfig::isReal()
похоже, это не служит никакой цели.