如何在C ++中使用另一个函数消除可变函数的歧义

时间:2017-01-25 20:08:40

标签: c++ overloading variadic-functions

假设我想要一个像这样的两个版本重载的函数:

a)void query(const string& s);,它向服务器发出SQL查询。

b)void query(const string& s,...);,它构建由格式字符串和要替换的参数给出的查询字符串。在内部,这个版本看起来像(我隐藏细节,不会使问题过于复杂):

va_list vargs;
va_start(vargs, s);
// ... call vsnprintf to build the query string
// ... call the first version with the query string
va_end(vargs);

请注意,我也希望这在MSVC和GCC中都有效。当然,通过如上所述的写作,由于含糊不清,我不能进行以下调用:

query("...");

为解决这种情况的歧义,我尝试了几种方法,但没有一种方法可行:

1)将它们改写为:

void query(const string& s) {
// ...
}

template<typename Value>
void query(const string& s, Value value,...) {
    va_list vargs;
    va_start(vargs, s);
    // ...
}

这在MSVC中编译并正常工作,但GCC抱怨警告:

  

va_start的第二个参数不是最后命名的参数”

即使我忽略了这个警告,它也不起作用。不知怎的,vargs无法捕获value参数,无论我尝试了什么:va_start(vargs, s)va_start(vargs, value)。在我看来,无论我们提供什么作为vargs的第二个参数,GCC始终只将未命名的参数带入va_start

2)将其重写为

void query(const string& s) {
// ...
}

template<typename... Values>
enable_if<(sizeof...(Values) > 0), void>::type
query(const string& s, Values value...) {
    va_list vargs;
    va_start(vargs, s);
    // ...
}

同样,这将编译并与MSVC一起使用。但GCC抱怨错误,第二个版本是可变参数模板而不是可变参数函数,并且不允许在那里使用va_start。似乎GCC中的va_start是内置的,而不是来自库。

有些人可以说实际上在2个版本中,第2版取代了第1版。这意味着如果我删除第一个版本并将其内部放入第二个版本,那么一切都没问题。但是我有充分的理由保留第一个版本:我希望只有一个字符串的调用直接进行,而不必不必要地调用vsnprintf。所以请不要这样建议我。

我还考虑过将第一个版本合并到第二个版本,然后在内部计算给定参数的数量以了解如何去做。但它似乎没有标准的方法来做到这一点。使用可变参数模板但不能使用可变参数函数来确定参数的数量。如果我切换到可变参数模板,我不能再在GCC中使用va_start

希望有人能帮忙!!

1 个答案:

答案 0 :(得分:1)

我还没有测试过这个,但是不会做以下工作吗?

void query_varargs(const string &s, ...) {
    va_list vargs;
    va_start(vargs, s);
    // ...
}

template<typename... Values>
enable_if<(sizeof...(Values) > 0), void>::type
query(const string& s, Values value...) {
    query_varargs(s, ...value);
}

即。将功能移动到不同的功能(query_varargs),然后将query的可变参数模板版本转发给它。