4

libc ++でGCCの実装されていない常にインライン化された可変個引数関数をバイパスする試みで、可変個引数テンプレート(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...に変換できない拡張が原因で、これは機能していtypeませんva_list {aka char*}。方法がない場合は、ハワードを信頼し、1つおよび2つの引数の常にインラインのテンプレートを実装する必要があります。これにより、必要なコードの量が実質的に2倍になります。

編集:おそらくそれをva_listに変換する方法std::tupleargsここで機能しますか?

4

3 に答える 3

3

あなたが尋ねている質問は紛らわしいと思うので、言い換えさせてください。

可変個引数テンプレートを使用して、可変個引数関数のインライン化をシミュレートする関数を記述します。

できません。 va_args多くの場合、スタックの最初のパラメーターに対するvoid *として実装されます(まさにこの理由から、可変個引数関数には少なくとも1つの非可変引数が必要であることに注意してください)。

適切な場所にパラメータを取得するには、コールスタックを操作する必要があります。これで、可変個引数テンプレート関数の引数がスタック上で必要な場所と同じ場所にある場合がありますva_argsが、その場合はテンプレート関数をインライン化しない必要があります。

可変個引数関数を常にインライン化することが実装されていない理由は、va_argsの実装が標準のスタックレイアウトを想定しているためだと強く思います。コンパイラがその関数をインライン化するには、スタックスペースを割り当て、パラメータを所定の位置にコピーする必要があります。保存するのは実際のjmp指示retだけです。

それは可能ですが、インライン化の利点の半分は蒸発します。さらに、コンパイラーは、可変個引数関数の強制インラインとして通常の関数呼び出しで使用するために、パラメーター受け渡しコード(つまりコンパイラー・コード)をより一般的な場所に持ち上げる必要があります。言い換えれば、それは制御フローを非常に複雑にし、利益が少ないかまったくないかを示します。

于 2011-09-27T19:15:58.753 に答える
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;
}
于 2011-09-25T14:30:20.343 に答える
1
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")ます。

于 2011-09-25T23:54:00.523 に答える