Возможно #if или #ifdef на основе сгенерированной препроцессором "вещи" - PullRequest
0 голосов
/ 03 сентября 2010

Я пытаюсь участвовать в некоторых C -процессорных шаблонизаторах только для того, чтобы типизировать некоторый код. Я попытался немного его упростить, поэтому этот пример кажется тривиальным и бессмысленным, но реальная проблема заключается в блокировке «включения».

Скажем, у меня есть файл "шаблона", который #include из других исходных файлов, которые определяют T_ELEMENT_TYPE перед включением шаблона.

// 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_ELEMENT_TYPE (чтобы не создавать повторяющиеся символы). Например, скажем так:

// 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;
}

Так что я ищу что-то, что я могу использовать в коде шаблона. Я предполагал, что это может выглядеть примерно так (хотя это не работает):

// 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_ELEMENT_TYPE.

Есть ли уловка, которую я могу использовать, чтобы получить этот эффект? Или я только что забронировал, так сказать, C -процессор?

1 Ответ

1 голос
/ 03 сентября 2010

Я думаю, что вы не в бронировании.Первый «аргумент» #define, имя макроса , не подлежит расширению макроса.Поэтому я не думаю, что препроцессор может определить другой символ в соответствии со значением T_ELEMENT_TYPE.Также препроцессор не может создать «список» уже увиденных типов и проверить его существование.

Поэтому я думаю, что include-guard должен быть за пределами файла:

#ifndef included_mytemplatefile_h_int
    #undef T_ELEMENT_TYPE
    #define T_ELEMENT_TYPE int
    #include "mytemplatefile.h"
    #define included_mytemplatefile_h_int
#endif

В качестве альтернативы, если заголовок файла шаблона объявляет только функцию SymbolFor_int, а не определяет ее, то многократное включение не является вредным.Вы могли бы иметь нормальную защиту включения для частей файла, которые не зависят от текущего значения T_ELEMENT_TYPE, включая определения PASTER, EVALUATOR, SYMBOLNAME.Вам понадобится отдельный файл шаблона, содержащий определения, которые программа (а не каждая единица перевода) должна иметь ровно один раз:

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

Затем добавьте template_int.o в списокфайлов, связанных с вашей программой.

...