C 可能是“基于生成的预处理器的if或ifdef”;“东西”;

C 可能是“基于生成的预处理器的if或ifdef”;“东西”;,c,c-preprocessor,C,C Preprocessor,我正在尝试进行一些C-仅预处理器的模板化工作,以便对某些代码进行类型专门化。我试着把它简化一点,所以这个例子看起来很琐碎,毫无意义,但真正的挑战是获得“include”阻塞 假设我有一个“模板”文件,该文件在包含模板之前从定义T#u元素#u类型的其他源文件中包含 // Template file... #ifndef T_ELEMENT_TYPE #error #define T_ELEMENT_TYPE #endif #define PASTER(x,y) x ## y #define EV

我正在尝试进行一些C-仅预处理器的模板化工作,以便对某些代码进行类型专门化。我试着把它简化一点,所以这个例子看起来很琐碎,毫无意义,但真正的挑战是获得“include”阻塞

假设我有一个“模板”文件,该文件在包含模板之前从定义T#u元素#u类型的其他源文件中包含

// Template file...
#ifndef T_ELEMENT_TYPE
#error #define T_ELEMENT_TYPE
#endif

#define PASTER(x,y) x ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SYMBOLNAME EVALUATOR(SymbolFor, T_ELEMENT_TYPE)

#ifndef SYMBOLNAMEISDEFINED
#define SYMBOLNAMEISDEFINED EVALUTOR(DEFINEDFOR, T_ELEMENT_TYPE)

int SYMBOLNAME(T_ELEMENT_TYPE arg)
{
    // do something with arg
    return 0;
}

#endif // Guard #ifdef
然后,我希望包含来自多个实例化站点的模板,但我只希望每个唯一的T_元素_类型生成一次模板化函数(以便不创建重复符号)。比如说:

// Template-using file...    
#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE float
#include "Template.c"
#undef T_ELEMENT_TYPE

#define T_ELEMENT_TYPE int
#include "Template.c"
#undef T_ELEMENT_TYPE

int someOtherFunc()
{
    int foo = 42;
    foo = SymbolForint(foo);
    float bar = 42.0;
    bar = SymbolForfloat(bar);
    return foo;
}
所以我正在寻找一些我可以在模板代码中使用的东西。我想象它可能看起来像这样(尽管这不起作用):

这个特殊的咒语阻止了模板的所有多个实例化,而不仅仅是T_元素类型的不同值


有什么技巧可以让我达到这个效果吗?或者说,我刚刚取消了预处理器预订?

我想你已经取消预订了。
#define
的第一个“参数”是宏名称,不受宏扩展的约束。因此,我认为预处理器不能根据t_元素的值定义不同的符号。预处理器也不能构造一个已有类型的“列表”,并检查其中是否存在

因此,我认为“包括”警卫必须在文件之外:

#ifndef included_mytemplatefile_h_int
    #undef T_ELEMENT_TYPE
    #define T_ELEMENT_TYPE int
    #include "mytemplatefile.h"
    #define included_mytemplatefile_h_int
#endif
或者,如果模板文件头只声明函数
SymbolFor\u int
,而不是定义它,那么多次包含并没有什么害处。您可以在文件中不依赖于t_ELEMENT_TYPE的当前值的部分(包括粘贴器、计算器、符号名的定义)周围设置一个普通的include防护。您需要一个包含定义的单独模板文件,程序(而不是每个翻译单元)只需要一次:

template_%.c :
    echo "#define T_ELEMENT_TYPE $*" > $@
    echo "#include \"mytemplatedefinitions.c\"" >> $@

然后将template_int.o添加到链接到程序中的文件列表中。

完全可以取消预订。#ifdef/#ifndef/定义的规则措辞谨慎,因此不可能对正在测试的标识符执行宏扩展,而这正是OP的想法发挥作用所需要的。
template_%.c :
    echo "#define T_ELEMENT_TYPE $*" > $@
    echo "#include \"mytemplatedefinitions.c\"" >> $@