Para invocar una función variádica con argumentos sin nombre de otra función variádica

3 minutos de lectura

Avatar de usuario de Richard
Ricardo

Tengo dos funciones variádicas como foo(format, ...) y bar(format, ...). Quiero implementar la función foo para que pueda invocar bar con la misma lista de argumentos que tiene. Eso es,

foo(format...)
{
 ...
 bar(format, ...);
}

Por ejemplo, invocando foo("(ii)", 1, 2) invocará bar con los mismos argumentos bar("(ii)", 1, 2). ¿Cómo debería esto foo ¿Se implementará la función?

PD: función bar es de una biblioteca heredada que no puedo cambiar su interfaz.

  • Duplicado de stackoverflow.com/questions/150543/…

    – Adam Rosenfield

    21 de marzo de 2011 a las 21:32

  • No sé lo que está tratando de lograr, pero estoy casi dispuesto a apostar que encontrará útiles las siguientes funciones de biblioteca estándar: vprintf(), vfprintf() y vsprintf().

    – Émile Cormier

    21 de marzo de 2011 a las 21:34


  • ¿Responde esto a tu pregunta? Reenviar una invocación de una función variádica en C

    – imz — Iván Zakharyaschev

    5 abr a las 16:46

AnT destaca con el avatar de usuario de Rusia
AnT apoya a Rusia

No se puede hacer, siempre y cuando todo lo que tenga sea un montón si funciona con ... argumentos

Tienes que planificar con anticipación cosas como esa e implementar cada función variable en dos etapas.

void vfoo(format, va_list *args) {
  /* Process `*args` */
}

void foo(format, ...) {
  va_list args;
  va_start(args, format);
  vfoo(format, &args);
  va_end(args);
}

Una vez que haya implementado cada una de sus funciones variádicas a través de un par de va_list * función y ... función, puede delegar las llamadas usando el va_list * versiones de las funciones

void vfoo(format, va_list *args) {
  ...
  vbar(format, args);
  ...
}

CCG puede construir llamadas a funciones en tiempo de ejecución.

foo() {
   void *args = __builtin_apply_args();
   void *ret = __builtin_apply(bar, args, ???);
    __builtin_return(ret);
}

??? es la cantidad de espacio de pila que ocupan los argumentos, lo que no es necesariamente trivial de calcular: deberá comprender cuáles son los argumentos y los detalles específicos de la arquitectura sobre cómo se pasan.

Otras extensiones de GCC permiten más trucos con macros y funciones en línea.

Respuesta corta: no puedes. Haz que la barra tome un va_list. Si está dispuesto a bloquear esto en un compilador específico, probablemente podría hacerlo con el ensamblado en línea, pero con C o C++ estándar no es posible.

Como regla general, siempre debe implementar sus funciones vararg en términos de va_list y luego hacer una función de puntos suspensivos de envoltura llamando al real va_list función.

  • No estoy de acuerdo con la ‘respuesta corta’. Se puede hacer en C++ 0x con plantillas variadas (ver respuesta en otro lugar). Sin embargo, solo voy a las etiquetas de preguntas, la de C ++ en particular 🙂

    – phooji

    21 de marzo de 2011 a las 21:08

  • @Max Lybbert: ¿Cuál de esos sería C++ 0x?

    – phooji

    21 de marzo de 2011 a las 21:19

  • @phooji: c ++ 0x no es c ++ (todavía), no responderá a una Q etiquetada con c ++ con c ++ 0x 🙂

    – Erik

    21 de marzo de 2011 a las 21:20

  • @Erik: Lo sé… pero ¿realmente quiere que el comité también dedique tiempo al nombre? :-pag

    – phooji

    21 de marzo de 2011 a las 21:32

  • @Max Lybbert: Ah. Estaba leyendo demasiado en tu comentario. Disculpas.

    – phooji

    21 de marzo de 2011 a las 23:24

avatar de usuario de phooji
phooji

Esto funciona en C++:

#include <iostream>

template<typename Format>
void meheer(const Format& format) {
  std::cout << format << std::endl;;
}

template<typename Format, typename Elt, typename ... Args>
void meheer(const Format& format, const Elt & e, const Args&... args) {
  std::cout << format << e;
  meheer(format, args...);
}

template<typename Format, typename ... Args>
void ohai(const Format& format, const Args&... args) {
  meheer(format, args...);
}

int main(int argc, char ** argv) {
  ohai(1,2,3);

  return EXIT_SUCCESS;
}

Producción:

12131

Por supuesto, esto es específico de C++0x, pero funciona en mi versión no muy reciente de gcc. Ver también: http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates

Actualizar Se agregó un ejemplo completo.

¿Ha sido útil esta solución?