C использует ряд аргументов в макро-переменной (реализация необязательного аргумента)

#c #macros

#c #макросы

Вопрос:

Я пишу некоторый макрос (да, я знаю, что это зло, но это помогает мне создавать более оптимизированный код), который выглядит следующим образом:

 #define HUGGLE_DEBUG(debug, verbosity) if (Huggle::Configuration::HuggleConfiguration->Verbosity >= verbosity) 
                                          Huggle::Syslog::HuggleLogs->DebugLog(debug, verbosity)
  

функция DebugLog(QString, unsigned int Verbosity = 1) имеет необязательный параметр детализации, и я хотел бы сделать его необязательным и в макросе, чтобы я мог вызывать

 HUGGLE_DEBUG("some debug text");
  

а также:

 HUGGLE_DEBUG("more verbose text", 10);
  

Возможно ли это как-то? Примечание: я использую вторую переменную в макросе, но если бы у меня ее не было, я мог бы просто заменить ее на 1

Моя идея состоит в том, чтобы создать из этого макрос variadic, который будет работать следующим образом:

 #define HUGGLE_DEBUG(debug, ...)    Syslog::HuggleLogs->DebugLog(debug, ##__VA_ARGS__)
  

который будет работать, но он не будет использовать оптимизацию, которую я сделал в первом

Комментарии:

1. Вы профилировали и проверили, что inline функции действительно оказываются хуже, чем макрос?

2. Проблема здесь в том, что я часто использую сложную конструкцию в качестве параметра, например DebugLog("some text " fc_that_returns_text() " bla") , который сам вызывает множество функций обработки текста. Я хочу избежать необходимости его вызывать, если только я действительно не нахожусь в режиме отладки (вот почему я хочу обернуть вызов функции в блок кода if), если функция была просто встроенной, параметр все равно должен быть сконструирован, тогда он просто не будет использоваться

3. Нет, если функция встроена, она заменяется на место. Таким образом, строковый аргумент будет оцениваться только при if передаче. Это принцип встраивания.

4. Конечно, встроенная функция HUGGLE_DEBUG должна быть определена в заголовочном файле, но это просто означает, что заголовочному файлу потребуется доступ к объявлению Verbosity and DebugLog . Для этого не требуется их определение.

Ответ №1:

Поскольку вы уже используете макрос, вы, вероятно, не будете возражать против очень сложного решения:

 #define HUGGLE_DEBUG(...) 
  if (Huggle::Configuration::HuggleConfiguration->Verbosity >= ((int)(bool)__VA_ARGS__)) 
    Huggle::Syslog::HuggleLogs->DebugLog(__VA_ARGS__)
  

При вызове с одним аргументом:

 HUGGLE_DEBUG("abc")

// expands to

if (Huggle::Configuration::HuggleConfiguration->Verbosity >= ((int)(bool)"abc"))
    Huggle::Syslog::HuggleLogs->DebugLog("abc")
  

(bool)"abc" есть true , так (int)(bool)"abc" есть 1 .

При вызове с двумя аргументами:

 HUGGLE_DEBUG("abc", 10)

// expands to

if (Huggle::Configuration::HuggleConfiguration->Verbosity >= ((int)(bool)"abc", 10))
    Huggle::Syslog::HuggleLogs->DebugLog("abc", 10)
  

(int)(bool)"abc", 10 использует оператор запятой, поэтому он вычисляет 10 .

Но, пожалуйста , пожалуйста, рассмотрите возможность использования inline функции вместо этого. Для этого нет необходимости использовать макрос.

Комментарии:

1. Это решение снижает производительность, поскольку в любом случае необходимо вычислить аргумент (во время if — первый аргумент, который не является текстом, но экземпляром QString , может быть сложным, включать конкатенацию через перегрузку оператора или некоторые другие функции, которые необходимо вызвать). Но последнее предложение правильное. Встроено и работает.

Ответ №2:

Существует также решение с повышением.Препроцессор:

 #define HUGGLE_DEBUG_1( debug ) HUGGLE_DEBUG_2( debug, 1 )
#define HUGGLE_DEBUG_2( debug, verbosity ) 
if( Huggle::Configuration::HuggleConfiguration->Verbosity >= verbosity) 
    Huggle::Syslog::HuggleLogs->DebugLog(debug, verbosity)

#define HUGGLE_DEBUG( ... ) BOOST_PP_OVERLOAD(HUGGLE_DEBUG_,__VA_ARGS__) (__VA_ARGS__)
  

Это более гибкий подход, чем подход с использованием оператора запятой, поскольку вы можете использовать любой аргумент по умолчанию, а не только 1 .

Тем не менее: используйте встроенные функции (или лямбды).

Комментарии:

1. 1 для менее сложного решения. Но обратите внимание, что мое может быть расширено и на другие значения по умолчанию: 4 amp; ~ !__VA_ARGS__ , например.