如何将C++和C变量参数一起使用?
通常,将C++11可变模板功能与函数一起使用时,要求基于可变的函数参数是函数参数列表中的最后一个。有一个例外;如果有C级可变参数,则它们是倒数第二个参数,而C级变量必须是最后一个。
template < typename ...Args >
int super_printf( Something x, Args &&...a, ... );
我有时会随机地想到C++,我想知道如何实现这样的函数。我首先想到了通常递归剥离a参数的方法,然后我记起C级别的varargs并不级联。我必须立即将它们转换为最终的va_list。
template < typename ...Args >
int super_vaprintf( Something x, std::va_list &aa, Args &&...a );
// Note that "aa" is passed by reference.
template < typename ...Args >
int super_printf( Something x, Args &&...a, ... )
{
std::va_list args2;
int result;
va_start( args2, XXX ); // (A)
try {
result = super_vaprintf( x, args2, std::forward<Args>(a)... );
} catch ( ... ) {
va_end( args2 ); // (1)
throw;
}
va_end( args2 ); // (2)
return result;
// Can (1) and (2) be compacted with RAII using a custom deleter lambda
// in std::unique_ptr or something? Remember that "va_end" is a macro!
}
通常的C++变量递归剥离发生在super_vaprintf
调用中。在第(A)行,XXX
、"a"或"a."的位置是什么?如果a为空会发生什么情况,x会转到那里吗?如果最后一个问题是真的,如果没有x;除了变量之外没有任何参数,我们就完蛋了吗?(如果为真,我们如何使代码在a为空时使用x,否则使用a?)
...
我只是在这里查看了我的C++11标准的副本,以寻求任何帮助。好像什么都没有。这将促使C++委员会回来修复这个问题,但我不确定是否有任何方法可以在不使用C++varargs的情况下调用这样的函数。我错了吗?函数调用可以同时使用C++和C varargs吗?或者,就愚蠢的(模板)实例化技巧而言,混合只对声明有用吗?
解决方案
当您调用其最后一个参数是包的函数时,所有参数都将成为该包的一部分。va_args
没有剩余内容。显式模板参数的使用具有误导性,因为它们不是独占的;它们只是位于隐式参数之前。
若要取消扣减,您需要一个推荐人:
(& super_printf<int, int>) ( 0L, 1, 2, 3, 4, 5 )
这是人为设计的,但现在您遇到了无法传递给va_start
的问题。
若要为用户提供合理的界面,只需在两个列表之间添加一个参数。
struct va_separator {}; // Empty; ABI may elide allocation.
template < typename ...Args >
int super_printf( Something x, Args &&...a, va_separator, ... );
thissuper_printf
将需要显式参数来定义包和显式分隔符参数。但您也可以提供一个公共函数,该函数按包接收其所有参数,然后查找分隔符并使用包含分隔符前面的包元素的显式参数列表转发到super_printf
。
相关文章