Хорошо, вот частичное решение!
Частично, потому что это не относится к действительно функциям с переменным числом
но для тех, которые принимают va_list в качестве аргумента.
Но я думаю, что полное решение не далеко.
Он основан на примерах, которые я нашел здесь:
Динамически создать va_list
https://bbs.archlinux.org/viewtopic.php?pid=238721
подделать va_list
http://confuseddevelopment.blogspot.com/2006/04/dynamically-creating-valist-in-c.html
Этот код успешно протестирован с gcc на linux и VC ++ 2008,
другие платформы также могут поддерживаться, но это зависит от вас.
Важным для меня было понимание того, что va_list - это не более чем упакованный массив,
которые могут быть заполнены данными динамически и могут быть переданы в функции, такие как
vprintf, vfprintf, vsprintf, которые принимают его в качестве аргумента.
Таким образом, передача векторных элементов одной из этих функций может работать, выделяя достаточно памяти
для векторных элементов и скопируйте их до вызова.
Сказав это, вот подход с динамическим размещением стека :
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <string>
#include <vector>
#include <alloca.h>
using namespace std;
class Format
{
typedef vector<unsigned long> ULVector;
ULVector _args;
string _format;
public:
Format(const char* format) : _format(format)
{}
Format &operator<<(int arg) {
_args.push_back((unsigned long)arg);
return *this;
}
Format &operator<<(const char* arg) {
_args.push_back((unsigned long)arg);
return *this;
}
string format() {
union {
va_list varargs;
unsigned long* packedArray;
} fake_va_list;
// malloc would do it as well!
// but alloca frees the mem after leaving this method
unsigned long *p = (unsigned long*)alloca(_args.size() * sizeof(unsigned long));
fake_va_list.packedArray = p;
ULVector::iterator i = _args.begin();
for (int n=0; i != _args.end(); i++, n++) {
p[n] = *i;
}
char buffer[512];
const char* fmt = _format.c_str();
vsprintf(buffer, fmt, fake_va_list.varargs);
// place a free(p) here if you used malloc
return string(buffer);
}
};
ostream& operator <<=(ostream &os, Format &obj) {
os << obj.format();
return os;
}
int main()
{
// we use '<<=' operator here which has lower precedence than '<<'
// otherwise we have to write
// cout << ( Format("\n%x %s %x %c\n") << etc. );
cout <<= Format("\n%x %s %x %c\n") << 0x11223344 << "VectorToVarArg" << 0xAABBCCDD << '!';
return 0;
}
Угадай, что он делает?
Это позволяет форматировать стиль printf (..) с параметрами, собранными в векторе.
Да, это не идеально, но делает то, что я хотел.
Кроме того, он охватывает две основные платформы: D
Кроме того, посмотрите на эту статью:
va_pass
http://www.codeproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a