Как я могу макросом # определить вызов статического метода в C ?

#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 then if 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() похоже, это не служит никакой цели.