У меня есть макрос, который выглядит так:
#define coutError if (VERBOSITY_SETTING >= VERBOSITY_ERROR) ods()
где ods () - это класс, который ведет себя аналогично cout, а VERBOSITY_SETTING - глобальная переменная. Есть несколько из них для разных настроек детализации, и это позволяет коду выглядеть примерно так:
if (someErrorCondition)
{
// ... do things relating to the error condition ...
coutError << "Error condition occurred";
}
И в этой структуре есть функция для установки подробности и т. д. Однако очевидный шаблон нарушается, если не использовать фигурные скобки в чем-то вроде этого:
void LightSwitch::TurnOn()
{
if (!PowerToSwitch)
coutError << "No power!";
else
SwitchOn = true;
}
из-за макроса превратится в это:
void LightSwitch::TurnOn()
{
if (!PowerToSwitch)
if (VERBOSITY_SETTING >= VERBOSITY_ERROR)
ods() << "No power!";
else
SwitchOn = true;
}
Что не является предполагаемой функциональностью оператора if.
Теперь я понимаю, как правильно исправить этот макрос, чтобы он не приводил к этой проблеме, но я хотел бы провести аудит кода и найти любое место, в котором есть этот шаблон «if (...) coutError < <...; else ", чтобы выяснить, есть ли другие случаи, когда это происходит, чтобы убедиться, что при исправлении макроса он действительно будет работать правильно.
Я могу использовать любой язык / инструмент, чтобы найти это, я просто хочу знать, как это сделать лучше всего.





Я думаю, что настоящая проблема заключается в использовании макроса, а не в коде, который подвергается предварительной обработке. Но я не думаю, что это тот ответ, который вы ищете.
Я бы нашел способ сделать это вообще без использования макросов - и если вы действительно используете условные компиляции, вы можете сделать это при вызове ods () - в зависимости от некоторого #define он может использовать любые функции, которые вы хотите.
только мои 0,02 доллара
поиск по регулярному выражению?
Что ж, проблема в том, что содержимое if может быть сложным, и операторы после coutError тоже могут быть сложными. Какое регулярное выражение можно использовать?
Вы можете попробовать - временно - изменить макрос на что-то вроде этого и посмотреть, что не компилируется ...
#define coutError {} if (VERBOSITY_SETTING >= VERBOSITY_ERROR) ods()
Пункты else теперь должны выдавать ошибки.
хорошо, но я думаю, что у него также могут быть проблемы с if, у которых нет elses? Хотя не уверен.
Это хорошая идея, но я не думаю, что ваша линия вызовет нужные проблемы. else будет по-прежнему присоединяться к оператору #defined if.
Думаю, вот что нужно: #define coutError {} ods ()
Я думаю, что все хорошие случаи использования макроса начинаются с символа "{" или ";".
Так что попробуйте это регулярное выражение:
[^{;]\s*coutError
Вам нужно будет включить многострочное сопоставление и поиск по целым файлам.
Возможно, вам понадобится взять больше вещей, чтобы найти нужную строку :-)
В качестве альтернативы изменение макроса - отличная идея, если мы сможем правильно решить что-то, что не сработает. Может быть, за блоком следует условный оператор:
#define coutError {} (VERBOSITY_SETTING >= VERBOSITY_ERROR)?(ods()):(nullstream())
(Но требует реализации оператора nullstream ().)
(В качестве альтернативы полностью избавьтесь от условного условия - как вы предлагаете, это комментарий к другому ответу @Roddy (в настоящее время выбранный ответ)).
p.s. Я знаю, что вы не спрашивали, но простой способ обернуть макрос, чтобы сделать его безопасным, - это использовать цикл do {} while(false).
Я не думаю, что вы можете обернуть этот конкретный макрос во что-нибудь и избавить его от этой проблемы. Это также отлавливает некоторые ложные срабатывания в этом "if (...) coutError <<" ... "; someotherstatement;" макрос не влияет на него, но это регулярное выражение его поймает.
Regex find = new Regex (@ "if [^ {};] + coutAgent [^ {};] +; [^ {};] + else", RegexOptions.Singleline); кажется, трюк
В ваших комментариях выше я вижу, что вы думаете об использовании шаблона в макросе, и я пока не могу комментировать (мне его не хватает на 9 баллов), так что ...
Что тебе мешает
#define CoutError(s) { if (VERBOSITY_SETTING >= VERBOSITY_ERROR){ ods(s); } }
А потом
void LightSwitch::TurnOn()
{
if (!PowerToSwitch)
CoutError("No power!");
else
SwitchOn = true;
}
И переопределите ods, чтобы принять строку, или, если вы не можете, просто определите функцию OdsHelper, которая принимает строку и тело которой просто ods << inString?
Я бы не стал играть с макросами, пытаясь имитировать синтаксис <<, если нет явного усиления. По крайней мере, с макросами, имитирующими синтаксис функции, мы больше используем и знаем, что должны писать блоки, чтобы предотвратить странные проблемы.
Вам действительно нужен синтаксис <<?
И действительно ли вам нужно ввести шаблон для этого простого поведения?
Ну и последнее - не используйте макросы.
Проблема больше в том, что он имитирует cout. Например: coutError << "Ошибка чтения:" << powerSetting << endl; И код не мой, это просто часть фреймворка, который мы используем там, где я работаю. Я согласен с тем, что макросы - это зло. Собственно, это то, что я цитирую, когда спорим :)
Отлично, теперь я могу прокомментировать :) Вы должны попытаться реорганизовать фреймворк, удалив хотя бы более проблемные макросы и попытаться установить для них стандарты. Распространенным стандартом является то, что макросы находятся в блоках. Расскажите об этом своей команде и попытайтесь убедить их. Если не можете, значит, вы застряли :)
Не пытайтесь найти все места в вашем коде, где возникает логическая ошибка - устраните проблему в ее источнике! Измените макрос, чтобы исключить возможность ошибки:
#define coutError if (VERBOSITY_SETTING < VERBOSITY_ERROR); else ods()
Обратите внимание, что здесь я перевернул тест, добавил пустой оператор для предложения then и поместил выходной объект в предложение else. Это по-прежнему позволяет вам использовать << foo << bar после макроса, и если у вас есть конечное предложение else, принадлежащее другому оператору if, оно будет правильно сопоставлено, поскольку оно расширяется следующим образом:
if (foo)
coutError << bar;
else
baz();
становится
if (foo)
if (VERBOSITY_SETTING < VERBOSITY_ERROR)
;
else
ods() << bar;
else
baz();
Это отличное исправление; даже проще, чем тот, который я собирался сделать. Тем не менее, основной смысл вопроса заключался в том, чтобы выяснить, появятся ли какие-либо ошибки, исправив проблему.
я собирался исправить это с помощью шаблона, так что: typedef ods <VERBOSITY_ERROR> coutError;