【问题标题】:C / C++ Preprocessor make header from name [duplicate]C / C ++预处理器根据名称制作标头[重复]
【发布时间】:2017-01-03 12:48:39
【问题描述】:

文件 Base.h

class Base {
}

文件 A.h

class A : public Base {
}

文件 B.h

class B : public Base {
}

文件 C.h

#define D_CLASS A

文件 C.cpp

#include "c.h"
#include D_CLASS##.h          // <--- how to make the header from class name?

Base * pBase = new D_CLASS() ;

这样做的动机...
支持不同操作系统的系统,每个操作系统都有头文件,告诉构建器要创建的类的名称,以提供某些功能。
当用户添加它的新操作系统时,他还需要使用该功能定义他的特定类名。

【问题讨论】:

  • 这里为什么有 c 标签?
  • 不要这样做。使用你的工具而不是反对它们。
  • 输入#include D_CLASS##.h 比输入#include a.h 容易得多吗?
  • 请告诉我这个的用例
  • 因为你的用户名是“教我”——生活中的一课——不要为自己的背部制造一根棍子

标签: c++ c-preprocessor


【解决方案1】:

你可以这样做:

#define PP_ADD_HDR_SUFFIX(x) PP_ADD_HDR_SUFFIX_IMPL(x)
#define PP_ADD_HDR_SUFFIX_IMPL(x) x.h

#define PP_QUOTE(x) PP_QUOTE_IMPL(x)
#define PP_QUOTE_IMPL(x) # x

#define CLASS_HEADER_NAME(name) PP_QUOTE(PP_ADD_HDR_SUFFIX(name))

#include "C.h"
#include CLASS_HEADER_NAME(D_CLASS)

Base * pBase = new D_CLASS();

基本上是这样展开的:

#include #D_CLASS.h

(第二个)'#'是创建一个字符串文字(文件名周围的引号),实际上不需要标记粘贴,只需宏扩展。

但是,正如其他人所提到的,您最好有一个好的用例。

过去,当我想支持“可配置”头文件(类的可配置介词/命名空间)时,我就这样做了。据我所知,最后看起来很乱:)。


同样,如果您想“预处理”系统标头(如 #include &lt;my_name.h&gt;),您可以这样做:

#define CLASS_NAME my_name

#define CLASS_SYSTEM_HEADER_NAME(name) CLASS_SYSTEM_HEADER_NAME_IMPL(name)
#define CLASS_SYSTEM_HEADER_NAME_IMPL(name) <name.h>

#include CLASS_HEADER_NAME(CLASS_NAME)

【讨论】:

  • 你真的尝试过这个吗?它不起作用(可能在 MSVC 等非标准预处理器上除外):Live on coliru: "error: pasteing "ctype" and "." does not give a valid preprocessing token"
  • 我在 MSVC 中尝试过它的工作原理。但是会在不同的编译器中尝试(也许我过去做的略有不同,因为我知道它在大多数编译器中都可以工作,我会尝试查找它)。
  • 更新了至少在 MSVC 和 GCC 中工作的版本(我测试过)。事实上,它实际上更简单,根本不需要标记粘贴:)(还测试了它是否适用于 coliru 示例)
  • 是的,关键是令牌粘贴不仅没有必要而且是非法的;文件路径(通常)不是有效的 token。
  • 第一个不适用于 clang,第二个适用于系统标头,我需要它:#include "my_header.h"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
相关资源
最近更新 更多