这是我的示例代码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,并且免费填写文件和行号。据我所知,除定义删除宏外,没有其他方法可以实现此功能。这是问题的症结所在。删除宏为我提供了强大的调试工具,但是它删除了我可以使用的有用的语言功能。
答案 0 :(得分:6)
您无法通过扩展宏来创建预处理令牌,该令牌是类似对象的宏的名称。 n3337的相关部分为[cpp.rescan]
。我在其中引用了第一段的缩短部分。
替换了替换列表中的所有参数,并进行了
#
和##
处理后,[...]然后,对生成的预处理令牌序列进行重新扫描,以查找更多要替换的宏名称。
尽管存在该问题,但从技术上来说,delete
被禁止为宏名,但无法阻止重新扫描时识别该宏名。
您可能将##
操作符确实使用它的参数而没有扩展的事实与##
的 result 的想法混为一谈。不进行宏扩展。
答案 1 :(得分:2)
您尝试做的事情是不可能的,因为Michael Karcher's answer指出:#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; }
};
(是的,这很丑陋,但是您首先要做的是有点丑陋,因此可能需要丑陋的代码才能使其正常工作。)
答案 2 :(得分:0)
大概您想使用宏,以便可以打开和关闭删除跟踪。如果仅在源代码上使用此功能,而不是尝试使用它来转换现有的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;
}
在gcc -E
下将TRACK_DELETES设置为0或1,看看这是否符合您的要求。
您将只保留裸露的delete
关键字,以便可以正确使用它。