2011-09-25 145 views
3

为了绕过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...,不能转换为typeva_list {aka char*}。如果没有办法,我必须信任Howard并实现一个和两个参数的always-inline模板,这将有效地增加所需代码的数量。

编辑:也许一种方式转换std::tupleargs是成为一个va_list将在这里工作?

+0

是不是定义了'va_list'实现的实现?所以至少没有可移植的方式来转换它,对吧?另外,'boost :: format'可以替代。 – pmr

+1

要明确,'args'根本不是'std :: tuple'。这是它自己独特的实体,我忘了一个名字。 'args ...'基本上扩展到'arg0,arg1,arg2,...,argN';换句话说,如果'vsprintf_l'接受了可变数量的参数,而不是单个'va_list'对象,那么你所做的就会起作用。 –

回答

3

我觉得你问的问题很混乱,所以让我重申一下。

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

它不能完成。 va_args经常作为一个void *被实现为堆栈中的第一个参数(注意可变参数函数由于这个原因需要至少有一个非可变参数)。

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

我强烈怀疑始终将可变参数函数内联的原因未实现是因为va_args的实现假定标准栈布局。为了让编译器内联该函数,它需要分配堆栈空间并复制参数。它唯一可以节省的是实际的jmpret说明。

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

1

你可以实现自己的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; 
} 
+0

这就是我最终做的事情,但是由于上面说了什么deft_code,并没有完全工作......代码被删除了,因此有问题的代码变得没有用,解决了直接的问题。 – rubenvb

0
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")通话。

+0

虽然我喜欢这个代码,但这不是问题的问题。虽然问题措辞不佳,但我不打算-1。 –