Nie jestem pewien, czy to działa dla wszystkich kompilatorów, ale jak dotąd zadziałało to dla mnie.
void inner_func(int &i)
{
va_list vars;
va_start(vars, i);
int j = va_arg(vars);
va_end(vars); // Generally useless, but should be included.
}
void func(int i, ...)
{
inner_func(i);
}
Możesz dodać ... do inner_func(), jeśli chcesz, ale go nie potrzebujesz. Działa, ponieważ va_start używa adresu danej zmiennej jako punktu początkowego. W tym przypadku podajemy odwołanie do zmiennej w func(). Więc używa tego adresu i czyta zmienne po tym na stosie. Funkcja inner_func() czyta z adresu stosu func(). Działa to tylko wtedy, gdy obie funkcje używają tego samego segmentu stosu.
Makra va_start i va_arg będą działać, jeśli jako punkt wyjścia nadamy im dowolny var. Jeśli chcesz, możesz przekazać wskaźniki innym funkcjom i użyć ich również. Możesz łatwo tworzyć własne makra. Wszystkie makra są typowymi adresami pamięci. Jednak tworzenie ich dla wszystkich kompilatorów i konwencji wywoływania jest denerwujące. Więc generalnie łatwiej jest używać tych, które pochodzą z kompilatora.
Twój przykład wygląda na nieco dziwny, ponieważ przekazujesz fmt zarówno do format_string(), jak i do fprintf(). Czy format_string() powinien jakoś zwrócić nowy łańcuch? –
Przykład nie ma sensu. Chodziło o pokazanie zarysu kodu. –
"powinno się googlować": nie zgadzam się. Google ma dużo hałasu (niejasne, często mylące informacje). Posiadanie dobrego (głosowanie w górę, zaakceptowana odpowiedź) na stackoverflow naprawdę pomaga! – Ansgar