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



为了绕过GCC在libc++中未实现的总是内联的变元函数,我想我可以将变元函数(比如snprintf,更准确地说,是*_l变体(封装在变元模板中以实现类似的效果。实例化将填充variadic函数的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;
}

我想用以下形式替换is:

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*},因此此操作不起作用。如果没有办法,我将不得不信任Howard,并实现一个和两个参数的始终内联模板,这将有效地使所需代码量增加一倍。

编辑:也许有一种方法可以将std::tuple(即args(转换为va_list?

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

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

这是不可能的。va_args通常被实现为堆栈上第一个参数的void*(注意,正是出于这个原因,变参数函数需要至少有一个非变参数(。

您需要操作调用堆栈以将参数放在正确的位置。现在的情况可能是,可变模板函数的参数在堆栈上与va_args想要的位置相同,但这需要模板函数不内联。

我强烈怀疑,总是内联variadic函数未实现的原因是因为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)...);
}

则调用CCD_ 10将导致对CCD_。

相关内容

  • 没有找到相关文章

最新更新