我正在使用gcc 4.6。 假设有一个参数向量v我必须传递给一个可变函数f(const char * format,...)。
这样做的一种方法是:
void VectorToVarArgs(vector<int> &v)
{
switch(v.size())
{
case 1: f("%i", v[0]);
case 2: f("%i %i", v[0], v[1]);
case 3: f("%i %i %i", v[0], v[1], v[2]);
case 4: f("%i %i %i %i", v[0], v[1], v[2], v[3]);
// etc...
default:
break;
}
}
// where function f is
void f(const char* format, ...)
{
va_list args;
va_start (args, format);
vprintf (format, args);
va_end (args);
}
问题当然是它不支持向量v中的任意数量的项目。 但是,我相信已理解va_lists原则上是如何工作的, 即通过从堆栈中读取参数,从“...”之前的最后一个命名参数的地址开始, 现在我认为应该可以将矢量项值复制到内存块(例如myMemBlock) 并将其地址作为'format'后的第二个参数传递。 显然,这需要myMemBlock按f()的预期结构化,即像堆栈一样。
最后,我不关心的事情:
答案 0 :(得分:3)
有一个&#34;创建假的va_list&#34; http://cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html部分。它适用于Cocoa,但你可能会在网上为GCC找到一些东西。
然后,我猜测你做了这样的事情:
#include <string>
#include <cstdio>
#include <vector>
#include <cstdarg>
using namespace std;
struct my_list {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
};
void f(const char* format, ...) {
va_list args;
va_start (args, format);
vprintf (format, args);
va_end (args);
}
void test(const vector<int>& v) {
string fs;
for (auto i = v.cbegin(); i !=v.cend(); ++i) {
if (i != v.cbegin()) {
fs += ' ';
}
fs += "%i";
}
my_list x[1];
// initialize the element in the list in the proper way
// (however you do that for GCC)
// where you add the contents of each element in the vector
// to the list's memory
f(fs.c_str(), x);
// Clean up my_list
}
int main() {
const vector<int> x({1, 2, 3, 4, 5});
test(x);
}
但是,我完全没有头绪。 :)
答案 1 :(得分:2)
你的反思不在适当的抽象层次。
当您说要将向量转换为变量参数列表时,这是因为采用变量参数列表的函数会对您感兴趣。
因此,真正的问题是,我怎样才能做到f
,但是从vector
开始?
除了将呼叫转发到f
之外,最终可能会开始解决方案,但这并不明显。
如果只是打印:
void f(std::vector<int> const& vi) {
bool first = true;
for (int i: vi) {
if (first) { first = false; } else { std::cout << ' '; }
std::cout << i;
}
}
或者,如果您可以访问外部库:
#include <boost/algorithm/string/join.hpp>
void f(std::vector<int> const& vi) {
std::cout << boost::join(vi, " ");
}
此时f
的兴趣不再明显。
答案 2 :(得分:2)
好的,这是部分解决方案! 部分,因为它不适用于真正的可变参数函数, 但是那些接受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
此代码已成功通过linux 和 VC ++ 2008上的gcc进行测试, 其他平台也可能受到支持,但这取决于你。
对我来说重要的见解是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
答案 3 :(得分:1)
根据您自己给出的答案判断,听起来您可以使用boost format。
示例:
#include <iostream>
#include <string>
#include <sstream>
#include <boost/format.hpp>
using namespace std;
using namespace boost;
template <typename T>
string formatted_str_from_vec(const T& v) {
ostringstream fs;
size_t count = 1;
for (const auto& i : v) {
if (&i != &v[0]) {
fs << " ";
}
fs << '%' << count << '%';
++count;
}
format fmtr(fs.str());
for (const auto& i : v) {
fmtr % i;
}
// looks like fmtr("%1% %2% %3% %4%") % v[0] % v[1] etc.
return fmtr.str();
}
int main() {
cout << formatted_str_from_vec(vector<int>({1, 2, 3, 4, 5, 6, 7, 8, 8, 10, 11, 12})) << endl;
cout << formatted_str_from_vec(vector<string>({"a", "b", "c"})) << endl;
format test1("%1% %2% %3%");
test1 % 1 % "2" % '3';
cout << test1.str() << endl;
format test2("%i %s %c");
test2 % 1 % "2" % '3';
cout << test2.str() << endl;
format test3("%1% %2%");
test3.exceptions(io::no_error_bits);
test3 % 'g';
cout << test3.str() << endl;
format test4("%%1%% = %1%");
test4 % "zipzambam";
cout << test4.str() << endl;
}
// g++ -Wall -Wextra printvector.cc -o printvector -O3 -s -std=c++0x
当然,打印出一个矢量并不是必需的。
答案 4 :(得分:0)
您可以使用STL算法for_each打印矢量的每个项目。