C ++停止预处理器宏扩展

时间:2019-05-08 16:57:39

标签: c++ c++11 preprocessor preprocessor-directive

这是我的示例代码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 个答案:

答案 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关键字,以便可以正确使用它。