簡體   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