这需要一个模板。
class Example<class T>
{
...class definition...
};
您问题最后一部分的直接答案 - “鉴于我不再处于宏定义中,我如何让粘贴和字符串化运算符工作” - 是“你不能”。这些运算符仅在宏中工作,因此您必须编写宏调用才能使它们工作。
补充:
@mackenir 说“模板不是一种选择”。为什么模板不是一个选项?该代码以老式的预标准、预模板方式模拟模板,这样做会造成很多痛苦和悲伤。使用模板可以避免这种痛苦——尽管会有转换操作。
@mackenir 问道“有没有办法让宏工作?” 是的,你可以,但你应该使用模板——它们更可靠和可维护。要使其与宏一起使用,您必须将包含的标头中代码中的函数名称作为宏调用。您需要经过一定程度的间接才能使其正常工作:
#define PASTE_NAME(x, y) PASTE_TOKENS(x, y)
#define PASTE_TOKENS(x, y) x ## y
#define TYPE_NAME Example
int PASTE_NAME(TYPE_NAME, _function_suffix)(void) { ... }
对于标记化和字符串化运算符,这种间接级别通常是必要的习惯用法。
@mackenir 的其他评论表明问题仍然存在。让我们把它具体化。
目前我正在使用宏在各种类上定义一堆字段和方法,如下所示:
class Example
{
// Use FIELDS_AND_METHODS macro to define some methods and fields
FIELDS_AND_METHODS(Example)
};
FIELDS_AND_METHODS 是一个使用字符串化和标记粘贴运算符的多行宏。
我想用下面的东西代替它
class Example
{
// Include FieldsNMethods.h, with TYPE_NAME preprocessor symbol
// defined, to achieve the same result as the macro.
#define TYPE_NAME Example
#include "FieldsNMethods.h"
};
好的。为了使这一点具体化,我们需要一个FIELDS_AND_METHODS(type)
多行的宏并使用标记粘贴(我不打算处理字符串化 - 不过将应用相同的基本机制)。
#define FIELDS_AND_METHODS(type) \
type *next; \
type() : next(0) { } \
type * type ## _next() { return next; }
幸运的是,这声明了“指向参数类型的指针”类型的成员、该类型的构造函数以及返回该指针的方法(在本例中为 Example_next)。
所以,这可能是宏 - 我们需要替换它,以便 '#include' 完成相同的工作。
fieldsNmethods.h 的内容变为:
#ifndef TYPE_NAME
#error TYPE_NAME not defined
#endif
#define FNM_PASTE_NAME(x, y) FNM_PASTE_TOKENS(x, y)
#define FNM_PASTE_TOKENS(x, y) x ## y
TYPE_NAME *next;
TYPE_NAME() : next(0) { }
TYPE_NAME * FNM_PASTE_NAME(TYPE_NAME, _next)() { return next; }
#undef FNM_PASTE_NAME
#undef FNM_PASTE_TOKENS
请注意,标头不会包含多重包含保护;它存在的理由是允许它被包含多次。它还取消定义了它的辅助宏以允许多次包含(好吧,因为重新定义是相同的,它们是“良性的”并且不会导致错误),并且我在它们前面加上FNM_
了宏的原始名称空间控制。这会生成我期望来自 C 预处理器的代码。并且 G++ 不会机智但会生成一个空的目标文件(因为我的示例代码中没有使用声明的类型)。
请注意,除了问题中概述的之外,这不需要对调用代码进行任何更改。我认为应该使用 SPOT“单点真理”原则(或干“不要重复自己”)来改进这个问题:
#define TYPE_NAME Example
class TYPE_NAME
{
// Include FieldsNMethods.h, with TYPE_NAME preprocessor symbol
// defined, to achieve the same result as the macro.
#include "FieldsNMethods.h"
};