繁体   English   中英

将可变参数模板粘贴到可变参数函数

[英]Gluing a variadic template to a variadic function

为了绕过GCC在libc ++中未实现的始终内联的可变参数函数,我想我可以将可变参数函数(如snprintf,更确切地说,* _l变量)包装在可变参数模板中以实现类似的效果。 实例化将填充可变参数函数的varargs,允许函数很好地内联。 问题是,我不知道编写可变参数模板的第一件事,我当然不知道如何将模板参数转换为单独的参数。

我想要替换的代码是以下形式:

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...无法转换为typeva_list {aka char*} 如果没有办法,我将不得不相信霍华德并实现一个和两个参数的始终内联模板,这将有效地使所需代码的数量翻倍。

编辑:也许一种方法将args转换为va_list的std::tuple可以在这里工作吗?

我认为你提出的问题令人困惑,所以让我重申一下。

您希望使用可变参数模板来编写模拟内联可变函数的函数。

它无法完成。 va_args通常被实现为堆栈中第一个参数的void *(注意,为了这个原因,变量函数至少需要有一个非可变参数)。

您需要操纵调用堆栈以获取正确位置的参数。 现在可能的情况是,可变参数模板函数的参数位于堆栈中与va_args希望它们在同一位置, va_args需要模板函数不被内联。

我强烈怀疑始终内联可变函数未实现的原因是因为va_args的实现假设标准堆栈布局。 为了使编译器内联该函数,它需要分配堆栈空间并复制参数。 它唯一能保存的是实际的jmpret指令。

它可以做到,但内联的一半好处蒸发了。 此外,编译器必须将参数传递代码(编译器代码)提升到更一般的位置,以便与常规函数调用一起使用,作为可变函数的强制内联。 换句话说,它使控制流程显着变得复杂,从小到无益。

您可以实现自己的sprintf_l

int __noninlined_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 = __noninlined_sprintf_l(__s, __l, __format, args...);
  return __res;
}
template<typename... T>
int
variadic(char* s, locale_t locale, const char* format, T&&... t)
{
    return __sprintf_l(s, locale, format, std::forward<T>(t)...);
}

然后调用variadic(s, l, "%d %s", 42, "Hello")将导致调用__sprintf_l(s, l, "%d %s", 42, "Hello")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM