#define DEFINE_TRANSACTION(T, NAME, ARGT) static T NAME(ARGT arg){ \
int encript = 0; /* encript result or no. Always 0 */ \
T result; \
. . .
}
Раньше encript мог быть равен только 0, теперь он может принимать значения: 0 или 1; и соответственно его необходимо явно указывать. Добавлять новый параметр в DEFINE_TRANSACTION нельзя. Вводить новое macro, что-то типа:
#define DEFINE_TRANSACTION_EX(OPT, T, NAME, ARGT) static T NAME(ARGT arg){ \
int encript = OPT & ENCRIPT_OPT_MASK; \
T result; \
. . .
}
крайне не желательно.
Было бы замечательно дать возможность пользователю macro писать так:
/* если encription не нужен; результат транзакции long long: */
DEFINE_TRANSACTION(long long, Transaction1, const char*)
/* должно разворачиваеться в: */
staic long long Transaction1(const char* arg) {
int encript = 0; /* do not encript result */long long result;
. . .
}
/* и так, если нужен; результат транзакции Encripted long long: */
DEFINE_TRANSACTION(ENCRIPT(long long), Transaction2, const char*)
/* должно разворачиваеться в: */
staic long long Transaction2(const char* arg) {
int encript = 1; /* encript result */long long result;
. . .
}
Здесь ENCRIPT(long long) должно каким-то образом стать причиной того, что переменной encript будет присвоено значение 1.
т.е. мне необходимо переписать исходное macro DEFINE_TRANSACTION так:
Вопрос собственно с реализацией макросов PULL_ENCRIPT и PULL_TYPE.
PULL_ENCRIPT(T) должно разворачиваться в 0;
PULL_ENCRIPT(ENCRIPT(T)) --> 1;
PULL_TYPE(T) --> T;
PULL_TYPE(ENCRIPT(T)) --> T;
Мне кажется, что где-то я этот трюк видела, но не припомню где, а может просто кажется что видела
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
#define ENCRIPT(T) T
#define PULL_ENCRIPT(arg) !strncmp(#arg, 7, "\"ENCRIPT")
#define DEFINE_TRANSACTION(T, NAME, ARGT) static T NAME(ARGT arg){ \
int encript = PULL_ENCRIPT(#T);\
T result; \
}
DEFINE_TRANSACTION(long long, nocrypt, const char*);
DEFINE_TRANSACTION(ENCRIPT(long long), crypt, const char*);
даст:
static long long nocrypt(const char* arg){ int encript = !strncmp("\"long long\"", 7, "\"ENCRIPT"); long long result; };
static long long crypt(const char* arg){ int encript = !strncmp("\"ENCRIPT(long long)\"", 7, "\"ENCRIPT"); long long result; };
Жульничество тут в том, что encript вычисляется не на этапе компиляции, а в ран-тайм. Но в приведенном коде ничего не говорт о том, что это недопустимо.
если бустовый препроцессор на С не работает или низзя, то cat оттуда легко изъять.
А синтаксис, если уж нельзя от макроса убежать, лучше изменить на DEFINE_TRANSACTION((ENCRYPT) param1, param2 etc).
Удачи.
Здравствуйте, Vamp, Вы писали:
V>Можно сжульничать вот так: . . .
Извиняюсь, что не уточнила, надо было это сразу сделать — хочется что бы всю 'работу' выполнил именно препроцессор. К томуже ни кто не запрещает пользователю обернуть DEFINE_TRANSACTION в свой макрос скажем:
А при использовании DEFINE_MY_TRANSACTION вместо DEFINE_TRANSACTION, в предложенном Вами варианте, препроцессор 'развернёт' ENCRIPT(T) до DEFINE_TRANSACTION. Соответственно в PULL_ENCRIPT всегда будет приходить только T ("long long" в нашем примере).
Здравствуйте, PIla, Вы писали:
PI>Спасибо, Erop:
PI>Шаблоны писать умеем, только язык в данном случае C
Не заметил в первоначальном сообщении.
А множество типов открытое?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Спасибо, суть ясна. Это то, что и требовалось. Но теперь меня начинает беспокоить вопрос: а на сколько это переносимо? Дело в том, что в приведённом Вами виде, с учётом исправления опечатки в строке
int encrypt = GET_TRANSACTION_ENCRYTION(ret_type); \
на
int encrypt = GET_TRANSACTION_ENCRYPTION(ret_type); \
без аналогичной правки тоже не компилируется. Подозреваю, что мой вариант не будет работать в VS. А есть и другие компиляторы, да и разные версии ещё. Эх, в общем будем пробовать.
А за идею и за то что меня "ткнули носом", ещё раз спасибо. А то у меня мЫшление всё как-то шло в другой плоскости
PI>Спасибо, суть ясна. Это то, что и требовалось. Но теперь меня начинает беспокоить вопрос: а на сколько это переносимо? Дело в том, что в приведённом Вами виде, с учётом исправления опечатки в строке
int encrypt = GET_TRANSACTION_ENCRYTION(ret_type); \
на
int encrypt = GET_TRANSACTION_ENCRYPTION(ret_type); \
, код не компилируется GCC 4.5.0.
И не должен Там требуется дополнительный уровень перевызова — особенности препроцессора. Для MSVC без разницы.
PI> А за идею и за то что меня "ткнули носом", ещё раз спасибо. А то у меня мЫшление всё как-то шло в другой плоскости
Возможно она пригодится
Не боитесь, такие тонкие особенности поведения препроцессора использовать? Как это потом поддерживать и переносить?
IMHO, надёжнее всего два макроса иметь.
Если над этим макросом ещё куча производных написана, и два макроса иметь плохо, то я бы typedef делал с каким-то фиксированным префиксом, и в CT его макросом бы проверял...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
А расскажите пожалуйста, как это работает. Непонятно, как макрос BOOST_PP_CAT(TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION x) на выходе дает 2 аргумента, которые требуют макросы GET_TRANSACTION_ENCRYPTION_I/GET_TRANSACTION_RET_TYPE_I.
Если передавать ENCRYPT(int), то в BOOST_PP_CAT должно попасть BOOST_PP_CAT( TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION (TRANSACTION_ENCRYPT) int ) так?
понятно, как макрос получает TRANSACTION_ENCRYPTION_TRANSACTION_ENCRYPTION_TRANSACTION_ENCRYPT, непонятно, как x(в данном случае int) становится вторым аргументом.
можно предположить, что препроцессор слово через пробел, не входящее в аргументы макроса передает как 2-й аргумент(x в данном случае как бы 3-й аргумент).
но пробую такой код:
#include<boost/preprocessor/cat.hpp>
#define get_type( type, name ) type
#define XXX(x)
int main()
{
get_type( BOOST_PP_CAT(in, t a) ) b = 1;
return 0;
}
не работает:
error: macro "get_type" requires 2 arguments, but only 1 given
AS>>Удачи.
E>Возможно она пригодится E>Не боитесь, такие тонкие особенности поведения препроцессора использовать? Как это потом поддерживать и переносить?
В смысле? Реализацию, работающую на большинстве известных мне препроцессоров, сделать просто. А остальное — по мере необходимости.
E>IMHO, надёжнее всего два макроса иметь.
Это вопрос к требованиям. Не нам их определять, вопрос был поставлен четко.
S>А расскажите пожалуйста, как это работает. Непонятно, как макрос BOOST_PP_CAT(TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION x) на выходе дает 2 аргумента, которые требуют макросы GET_TRANSACTION_ENCRYPTION_I/GET_TRANSACTION_RET_TYPE_I.
Все дело в волшебных запятых
S>Если передавать ENCRYPT(int), то в BOOST_PP_CAT должно попасть BOOST_PP_CAT( TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION (TRANSACTION_ENCRYPT) int ) так? S>понятно, как макрос получает TRANSACTION_ENCRYPTION_TRANSACTION_ENCRYPTION_TRANSACTION_ENCRYPT, непонятно, как x(в данном случае int) становится вторым аргументом.
S>можно предположить, что препроцессор слово через пробел, не входящее в аргументы макроса передает как 2-й аргумент(x в данном случае как бы 3-й аргумент).
Тут дело не в этом. Просто разные пути вычисления в зависимости от наличия (MACRO) перед аргументом.
S>но пробую такой код:
Там все не так... Никакой магии с передачей аргументов тут нет — всего лишь используется свойство препроцессоров при обработке макроса вычислять аргументы, т.ч. выполняя получившиеся в результате раскрытия макросы. После раскрытия TRANSACTION_ENCRYPTION_I(x) получается (0, arg) либо (1, arg). Дальше все очевидно (ну, кроме того, что некоторых препроцессоров надо еще раз явно заставить раскрыть макросы, добавив вложенность вызовов, что делает по умолчанию BOOST_PP_CAT).
Здравствуйте, Andrew S, Вы писали:
S>>А расскажите пожалуйста, как это работает. Непонятно, как макрос BOOST_PP_CAT(TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION x) на выходе дает 2 аргумента, которые требуют макросы GET_TRANSACTION_ENCRYPTION_I/GET_TRANSACTION_RET_TYPE_I.
AS>Все дело в волшебных запятых
а.... разобрался. сначала запятые не заметил.
тогда для меньшего запутывания можно было бы запятую возле BOOST_PP_CAT(...), перемесить к определению единицы:
S>>>А расскажите пожалуйста, как это работает. Непонятно, как макрос BOOST_PP_CAT(TRANSACTION_ENCRYPTION_, TRANSACTION_ENCRYPTION x) на выходе дает 2 аргумента, которые требуют макросы GET_TRANSACTION_ENCRYPTION_I/GET_TRANSACTION_RET_TYPE_I.
AS>>Все дело в волшебных запятых
S>а.... разобрался. сначала запятые не заметил. S>тогда для меньшего запутывания можно было бы запятую возле BOOST_PP_CAT(...), перемесить к определению единицы:
Да, так можно. Хотя, в таком коде меньше запутать уже вряд ли можно