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。 –