Замена символа открытой скобки в макросе C/C++

Мне нужен макрос для передачи __FILE__ и __LINE__ функции с аргументами по умолчанию. Это открыло банку червей, поскольку аргументы по умолчанию с макросами либо невозможны, либо очень запутаны, и мне нужно поддерживать как GCC, так и MSVC, если это возможно:

class Class
{
#ifdef _DEBUG

   int Function(int a, int b = 10, int c = 20) { return a + b + c; }

#else

   int DebugFunction(const char* filename, int lineNo, int a, int b = 10, int c = 20)
   {
      printf("%s (%i) a:%i b:%i c:%i\n", filename, lineNo, a, b, c);
      return a + b + c;
   }

   //Not possible
   #define Function( DebugFunction(__FILE__, __LINE__

#endif
}

Я пытался \экранировать ( безрезультатно. Кодовая база огромна, поэтому исправление отсутствующих аргументов по умолчанию или создание нескольких макросов не является популярным вариантом.

Любые решения?


person Catch33    schedule 06.02.2012    source источник
comment
Почему вы сказали, что аргументы по умолчанию с макросами либо невозможны, либо очень запутаны? Это неправда и не имеет отношения к вашей проблеме. Я думаю, вам просто нужен простой способ автоматически добавлять __FILE__ и __LINE__ к вызовам определенных функций. Это ваша цель?   -  person Aaron McDaid    schedule 07.02.2012
comment
Да, это именно то, чего я пытался (и мне удалось) добиться. Решение KerrekSB сработало. Я думаю, что в своей голове я делал это более сложным, чем должно было быть.   -  person Catch33    schedule 07.02.2012


Ответы (4)


Вы можете сделать вариативный макрос:

#define Function(...) DebugFunction(__FILE__, __LINE__, __VA_ARGS__)

Поскольку вы не можете «перегружать» макросы, это может быть вашим лучшим выбором.

person Kerrek SB    schedule 06.02.2012
comment
Как я могу подсчитать количество переданных аргументов? Мне все еще нужно заменить НЕ переданные аргументы некоторыми значениями по умолчанию. - person Catch33; 07.02.2012
comment
@Catch33: Вы не можете, и вы просто не беспокоитесь. Вы все равно получите ошибку компилятора, если используете его неправильно. (Но, конечно, решение ttd намного лучше.) - person Kerrek SB; 07.02.2012
comment
Я не понимаю - вы не получаете ошибку компилятора из-за неправильного использования вариационного макроса, это ад во время выполнения. Если бы в списке был только один аргумент, я не могу вытащить 3 аргумента... - person Catch33; 07.02.2012
comment
@Catch33, просто используйте стандартную функциональность аргументов по умолчанию в C++. void foo_(const char * file, int lineno, int x, int y=3, int z=5) и #define foo(...) foo_(__FILE__, __LINE__, __VA_ARGS__). Я что-то неправильно понял? - person Aaron McDaid; 07.02.2012
comment
Если пользователь вызывает функцию, например: foo(12, 20); Переданы только два аргумента. Мне нужно компенсировать остальные аргументы. Компилятор не будет явно расширять макрос, чтобы включить отсутствующие (по умолчанию) аргументы. - person Catch33; 07.02.2012
comment
@Catch33, макросы работают не так, как ты думаешь. Просто попробуйте. Он будет работать с аргументами по умолчанию или без них :-) - person Aaron McDaid; 07.02.2012
comment
+1. Просто имейте в виду, что это будет работать только до тех пор, пока однажды вы не решите, что a также получит значение по умолчанию. - person Jens Gustedt; 07.02.2012
comment
@KerrekSB Ну, я немного смущен, и я должен извиниться перед вами - это сработало просто отлично. Я проводил свои исследования весь день (некоторые ресурсы говорят, что аргументы по умолчанию с макросами невозможны), фактически не пытаясь это сделать... - person Catch33; 07.02.2012
comment
@Catch33: Не смущайся; Я тоже думал, что вариативные макросы ведут себя как вариативные аргументы функций. Я узнал что-то новое сегодня. Вот почему я так люблю этот сайт. - person Emile Cormier; 07.02.2012
comment
@EmileCormier Я читал и перечитывал статьи, на которых я основывал свои первоначальные ответы, и это щелкнуло - аргументы по умолчанию ВНУТРИ ОПРЕДЕЛЕНИЯ МАКРО невозможны. Внутри функции, которую я пытаюсь заменить, это совсем другая история, и этот пример отлично подходит для того, чего я пытаюсь достичь. - person Catch33; 07.02.2012
comment
@JensGustedt - отмечено. Я уверен, что это не относится к реальному коду, в котором я планирую использовать это, но я буду иметь это в виду. - person Catch33; 07.02.2012
comment
@JensGustedt: Когда это произойдет, вы можете использовать расширение GCC DebugFunction(__FILE__, __LINE__, ##__VA_ARGS__) или использовать подлую магию препроцессора Boost. - person Kerrek SB; 07.02.2012
comment
@KerrekSB, ваша первая идея не работает для всех компиляторов, упомянутых в ОП, а для второй, к моему разочарованию, он попросил решение без этой магии препроцессора. - person Jens Gustedt; 07.02.2012
comment
@JensGustedt: Ну... все это скрыто за красивой оболочкой полировки Boost. Вы видели BOOST_OPTIONAL_COMMA? - person Kerrek SB; 07.02.2012

Одним из вариантов было бы переписать вашу основную функцию Function следующим образом:

int Function(const char* filename, int lineNo, int a, int b = 10, int c = 20)
{
   #ifdef _DEBUG
       printf("%s (%i) a:%i b:%i c:%i\n", filename, lineNo, a, b, c);
   #endif
   return a + b + c;
}

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

Надеюсь это поможет!

person templatetypedef    schedule 06.02.2012
comment
Ха-ха, самое простое решение часто оказывается лучшим! - person Kerrek SB; 07.02.2012
comment
Простой, но эффективный, но я боюсь, что он не будет популярен среди команды, поскольку это означает гигантский поиск/замену в огромной кодовой базе, а также заставляет их писать (ФАЙЛ, LINE каждый раз, когда они используют эту функцию. - person Catch33; 07.02.2012

Я не совсем уверен, что понимаю, что вы пытаетесь сделать, но мог бы вариативный макрос поможет?

person John Carter    schedule 06.02.2012
comment
Вдоль правильных строк, но я не мог сосчитать количество переданных вари-аргументов, чтобы выбрать правильный макрос - person Catch33; 07.02.2012
comment
Да, оказывается, мне вообще не нужно было считать количество аргументов. Смотрите ответ KerrekSB. - person Catch33; 07.02.2012

Не большой парень С++, но пробовали ли вы что-то вроде (в псевдокоде)

#ifdef debug

#define Function(args) _Function(__file__, __line__, (args))
int _Function(char *file, int line, args) { /* code */ }

#else

#define Function(args) _Function(args)
int _Function(args) { /* code */ }

#endif

Конечно, сама функция должна иметь возможность принимать несколько версий аргументов; Я действительно не вижу другого способа сделать это.

person tbert    schedule 06.02.2012
comment
Опять же, по правильным линиям, но я не могу сосчитать количество аргументов, переданных в - person Catch33; 07.02.2012
comment
@tbert: Чтобы это сработало, я думаю, что Function нужно будет вызывать следующим образом: Function((arg1, arg2, arg3)). - person Emile Cormier; 07.02.2012
comment
@Catch33: я не уверен, что вы имеете в виду под подсчетом количества аргументов? вам не хватает моего комментария в псевдокоде выше? - person tbert; 07.02.2012
comment
@Catch33 отредактировал часть, которую я пропустил раньше; извинения за неясность - person tbert; 07.02.2012
comment
@tbert: псевдокод выглядит логично, но на практике не работает - в определении функции есть аргументы DEFAULT, они не учитываются при раскрытии макроса. Если я передам только один аргумент, когда я вытащу остальные из списка (args), они будут мусором. - person Catch33; 07.02.2012
comment
@tbert: я не нападал на вас, я предоставлял дополнительную актуальную информацию, чтобы помочь ОП (и другим, кто наткнется на этот пост) найти решение. :-) - person Emile Cormier; 07.02.2012
comment
@EmileCormier: не думал, что ты такой, просто уточнял :) - person tbert; 07.02.2012
comment
@Catch33: тогда я думаю, что вас облили шлангом, сэр; если вы не можете получить какую-либо версию #define Function _Function(file, line, (args)) работающую, я думаю, вы, возможно, наткнулись на место, где желание и возможность терпят неудачу пересекаться. - person tbert; 07.02.2012
comment
@tbert - Оказывается, этот образец был правильным. Я делал это в своей голове намного сложнее, чем должно было быть, и теперь я вижу, что статьи, в которых говорится, что аргументы по умолчанию в макросах невозможны, просто означают, что аргументы по умолчанию ВНУТРИ макросов невозможны. Спасибо за помощь! - person Catch33; 07.02.2012