将可变参数模板粘合到可变参数函数
为了绕过 GCC 在 libc++ 中未实现的始终内联可变参数函数,我想我可以将可变参数函数(如 snprintf,更准确地说是 *_l 变体)包装在可变参数模板中以实现类似的效果。实例化将填充可变参数函数的可变参数,从而允许函数很好地内联。问题是,我不知道编写可变参数模板的第一件事,而且我当然不知道如何将模板参数转换为单独的参数。
我要替换的代码的形式为:
int __sprintf_l(char *__s, locale_t __l, const char *__format, ...) {
va_list __va;
va_start(__va, __format);
int __res = vsprintf_l(__s, __l, __format, __va);
va_end(__va);
return __res;
}
我想替换为以下形式的代码:
template<typename... Args>
int __sprintf_l(char *__s, locale_t __l, const char *__format, Args... args) {
int __res = vsprintf_l(__s, __l, __format, args...);
return __res;
}
这不起作用,因为无法转换扩展的 args...
输入
到va_list {aka char*}
。如果没有办法,我将不得不相信 Howard 并实现一个和两个参数的始终内联模板,这实际上会使所需的代码量增加一倍。
编辑:也许将 args
的 std::tuple
转换为 va_list 的方法在这里可以工作?
In an attempt to bypass GCC's unimplemented always-inlining variadic functions in libc++, I thought I could maybe wrap the variadic functions (like snprintf, more precisely, the *_l variant) in a variadic template to achieve a similar effect. An instantiation would fill in the variadic function's varargs, allowing the function to be nicely inlined. The problem is, I don't know the first thing about writing variadic templates, and I certainly don't know how to turn the template arguments into seperate arguments.
The code I'm looking to replace is of the form:
int __sprintf_l(char *__s, locale_t __l, const char *__format, ...) {
va_list __va;
va_start(__va, __format);
int __res = vsprintf_l(__s, __l, __format, __va);
va_end(__va);
return __res;
}
I'd like to replace is with something of the form:
template<typename... Args>
int __sprintf_l(char *__s, locale_t __l, const char *__format, Args... args) {
int __res = vsprintf_l(__s, __l, __format, args...);
return __res;
}
This is not working, due to the expanded args...
which cannot be converted to type
to va_list {aka char*}
. If there is no way, I'll have to trust Howard and implement one-, and two-argument always-inline templates, which would effectively double the amount of needed code.
EDIT: perhaps a way to convert the std::tuple
that args
is into a va_list would work here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为你问的问题很令人困惑,所以让我重申一下。
您想要使用可变参数模板来编写模拟内联可变参数函数的函数。
这是不可能的。 va_args 通常被实现为堆栈上第一个参数的 void*(请注意,正是由于这个原因,可变参数函数需要至少有一个非可变参数)。
您需要操作调用堆栈才能将参数放在正确的位置。现在,可变参数模板函数的参数可能位于堆栈上与 va_args 想要的位置相同的位置,但这需要模板函数不被内联。
我强烈怀疑总是内联可变参数函数未实现的原因是因为 va_args 的实现假设标准堆栈布局。为了让编译器内联该函数,需要分配堆栈空间并就地复制参数。它唯一能保存的是实际的
jmp
和ret
指令。这是可以做到的,但是内联的一半好处就消失了。此外,编译器必须将参数传递代码(即编译器代码)提升到更通用的位置,以便与常规函数调用一起使用,作为强制内联可变参数函数。换句话说,它使控制流程显着复杂化,但几乎没有任何好处。
I think the question you're asking is confusing so let me restate it.
You want to use variadic templates to write a function that simulates inlining a variadic function.
It cannot be done.
va_args
is often implemented as a void* to the first parameter on the stack (note variadic functions are required to have at least one non-variadic argument for exactly this reason).You would need to manipulate the call stack to get the parameters in the right place. Now it might be the case that the variadic template function's arguments are on the stack in the same location as
va_args
would want them but that would require the template function to not be inlined.I strongly suspect the reason always inlining variadic function is unimplemented is because of the implementation of va_args assume standard stack layout. For the compiler to inline that function it would need to allocate stack space and copy the parameters in place. The only thing it would save is actual
jmp
andret
instructions.It could be done, but half of the benefits of inlining evaporate. Further the compiler will have to hoist the parameter passing code (compiler code that is) to a more general location for use with regular function calls as forced inline of variadic functions. In other words it complicates the control flow significantly for small to no benefit.
你可以实现你自己的 sprintf_l
并调用它
You could implement your own sprintf_l
And call that instead
然后调用
variadic(s, l, "%d %s", 42, "Hello")
将导致调用__sprintf_l(s, l, "%d %s", 42,“你好”)。
Then calling
variadic(s, l, "%d %s", 42, "Hello")
would result in a call to__sprintf_l(s, l, "%d %s", 42, "Hello")
.