Расширение макроса препроцессора C ++ Stop - PullRequest
5 голосов
/ 08 мая 2019

Вот мой пример кода https://godbolt.org/z/VKgKik

#define delete MyCustomDelete(__FILE__, __LINE__), delete

#define CAT(X,Y) CAT2(X,Y)
#define CAT2(X,Y) X##Y
#define CAT_3(X,Y,Z) CAT(X,CAT(Y,Z))    


class A {
    A() = CAT_3(de,le,te);
};

Пример Godbolt настроен для отображения выходных данных препроцессора.Цель состоит в том, чтобы в конце прохода препроцессора я хотел, чтобы выходной код был

class A {
    A() = delete;
};

, в данный момент вместо него отображается ThisShouldNotshowUp.Я думал, что использование оператора ## остановит повторное расширение препроцессора, но этого не произошло.

Я понимаю, что удаление "#define delete" решило бы проблему, но мне нужно это определение там.Причина, по которой я создал макрос с тем же именем, что и при удалении, заключается в том, что я хочу иметь возможность отслеживать новости и удалять, и в случае утечки памяти я вижу, какая строка кода ее исправила.Таким образом, этот макрос означает, что я могу продолжать использовать ключевое слово delete в своем коде, а номера файлов и строк заполняются бесплатно.Насколько я знаю, нет другого способа достичь этой функции, кроме как определенным макросом удаления.В этом суть проблемы.Макрос удаления дал мне мощный инструмент отладки, но он удалил полезную языковую функцию для меня.

Ответы [ 3 ]

6 голосов
/ 08 мая 2019

У вас нет шансов создать токен предварительной обработки, представляющий собой имя объектоподобного макроса, из раскрываемого макроса. Соответствующий раздел n3337 - [cpp.rescan]. Я цитирую сокращенную часть первого абзаца в нем.

После замены всех параметров в списке замены и обработки # и ## [...]. Затем результирующая последовательность токенов предварительной обработки повторно сканируется [...], чтобы заменить имена других макросов.

Несмотря на проблему, что delete технически запрещено быть именем макроса, нет способа предотвратить распознавание имени макроса при повторном сканировании.

Вы, вероятно, перепутали тот факт, что оператор ## использует его параметры без раскрытия, полагая, что результат из ## не подвергается макроразложению.

2 голосов
/ 08 мая 2019

То, что вы пытаетесь сделать, невозможно, так как Ответ Михаэля Карчера гласит: #define delete уже делает программу плохо сформированной и расширяет объектоподобный макрос (вне собственного расширения)Нельзя избежать.

Однако для вашего конкретного случая использования, подробно описанного в вопросе, возможен обходной путь.Вы можете поместить ваш #define delete в заголовочный файл (назовем его debug_delete.hxx), например:

#ifdef delete
# undef delete
#endif
#define delete MyCustomDelete(__FILE__, __LINE__), delete

Затем создайте еще один заголовочный файл (назовем его normal_delete.hxx):

#ifdef delete
# undef delete
#endif

Обратите внимание, в частности, что в этих заголовках нет механизма предотвращения множественного включения;на самом деле, мы хотим, чтобы они включались произвольное количество раз.

Затем закрутите код, который должен использовать = delete; в соответствующих директивах #include:

class A {
#include "normal_delete.hxx"
    A() = delete;
#include "debug_delete.hxx"
    ~A() { delete p; }
};

(Да, это уродливо, но то, что вы делаете, во-первых, некрасиво, поэтому для его работы может потребоваться некрасивый код).

0 голосов
/ 08 мая 2019

Предположительно, вы хотите использовать макрос, чтобы вы могли включать и выключать отслеживание удаления.Если вы используете это только в своем источнике и не пытаетесь настроить его для преобразования существующего C ++, вы можете использовать функциональный макрос, чтобы выполнить необязательное отслеживание, которое вы хотите.

#define TRACK_DELETES 0
#if TRACK_DELETES
  #define DELETE( a ) \
    do { MyCustomDelete( __FILE__, __LINE__ ); delete (a); } while (0)
  #define DELETEALL( a ) \
    do { MyCustomDelete( __FILE__, __LINE__ ); delete [] (a); } while (0)
#else
  #define DELETE( a ) do { delete (a) ; } while(0)
  #define DELETEALL( a ) do { delete [] (a) ; } while(0)
#endif

int main(){

  DELETE( A );
  DELETEALL( B );

  return 0;
}

Проверьте, выполняет ли это то, что вы хотите, с TRACK_DELETES, установленным в 0 или 1 в gcc -E.

. Вы можете оставить только одно ключевое слово delete, чтобы его можно было использовать соответствующим образом.

...