Вариативные макросы с перегрузкой функций

У меня есть функция:

SendMsg(int x, string y, ...) { /*some code*/ }

У меня есть макрос:

FOO(X, STRING, ...) SendMsg(X, STRING "%s %d", ##__VA_ARGS__, "xyz", 123)

так что я могу иметь что-то вроде этого:

FOO(1000, "Note that line %d containing %d words is invalid", 5, 10);

расширен до

SendMsg(1000, "Note that line %d containing %d words is invalid" "%s %d", 5, 10, "xyz", 123);

Иногда у меня что-то вроде этого:

FOO(1000, "String without variables");

который должен быть расширен как

SendMsg(1000, "String without variables" "%s %d", "xyz", 123)

Макрос пока работает нормально.

Но иногда у меня что-то вроде этого:

FOO(1000);

который должен быть расширен как

SendMsg(1000, "%s "%d", "xyz", 123);

Но это не работает. Я получаю сообщение об ошибке, что "макросу FOO требуется 3 аргумента, но задан только 1". Любые идеи?


person user2524261    schedule 10.12.2015    source источник
comment
вы не можете передать пустую строку в качестве второго аргумента макроса?   -  person rahul.deshmukhpatil    schedule 10.12.2015
comment
Я хочу избежать этого. Или введите другой макрос, который сделает это.   -  person user2524261    schedule 10.12.2015
comment
В этом случае макрос может содержать только 1-й аргумент как фиксированный. Хотя, начиная со 2-го, все вариативные. Таким образом, в самом макросе вы можете отдельно извлечь 2-й аргумент в макрос и передать его как 2-й аргумент SendMsg. в то время как 3-й аргумент функции будет %s %d, а затем все остальные вариады + xyz + 123.   -  person rahul.deshmukhpatil    schedule 10.12.2015
comment
как извлечь второй аргумент? и как мне получить все остальные вариады?   -  person user2524261    schedule 10.12.2015


Ответы (2)


что вам нужно сделать, это изменить подпись SendMsg.

SendMsg(int x, char *secondFmt, char *xyx, int no123, ...)
{
     // Print the string in buffer with ##__VA_ARGS__ using sprintf. first 
     // argument extracted from will be string only. otherwise sprintf will fail
     va_start(args, no123);
     const char *fmt = va_arg(args, const char *);
     bytesWrote = sprintf(buffer, fmt, args);
     sprintf(buffer + bytesWrote, secondFmt, xyz, no123);
     va_end(args);
}

Теперь Фу будет выглядеть

FOO(X, ...) SendMsg(X, "%s %d", "xyz", 123, ##__VA_ARGS__)

Что я сделал, так это сначала распечатал сообщение из ##__VA_ARGS__, а затем из "%s %d" части. в порядке, обратном тому, как аргументы передаются SendMsg. Непроверено, так что просто настройте код.

Если вы не хотите изменять SendMsg, посмотрите, работает ли приведенный ниже код.

 FOO(X, ...) {\
  va_start(args, no123);\
  const char *fmt = va_arg(args, const char *);\
  SendMsg(X, fmt "%s %d", "xyz", 123, args);\
  va_end(args);\
}\

если нет, просто напишите два макроса:

FOO_FMT(X, STRING, ...) SendMsg(X, STRING"%s %d", "xyz", 123, ##__VA_ARGS__)
FOO(X) SendMsg(X, "%s %d", "xyz", 123)
person rahul.deshmukhpatil    schedule 10.12.2015
comment
Нет, я не хочу изменять SendMsg. Также у меня есть условное расширение макроса. Я могу или не могу пройти 123. - person user2524261; 10.12.2015
comment
Посмотрите, могут ли работать другие два метода. если нет, я не думаю, что мог бы помочь вам больше. - person rahul.deshmukhpatil; 10.12.2015

С вариативным шаблоном (С++ 11) вы можете делать перегрузки, например:

template <typename... Ts>
void FOO(int x, const std::string& format, Ts... args)
{
    SendMsg(x, format + "%s %d", args..., "xyz", 123);
}

void FOO(int x)
{
    SendMsg(x, "%s %d", "xyz", 123);
}

Демо

person Jarod42    schedule 10.12.2015