14

次のメタ関数があるとします。

template <typename T>
struct make_pair {
    using type = std::pair<
        typename std::remove_reference<T>::type,
        typename std::remove_reference<T>::type
    >;
};

代わりにこれ(または他の何か)を行うとコンパイル速度が向上しますか?

template <typename T>
struct make_pair {
    using without_reference = typename std::remove_reference<T>::type;
    using type = std::pair<without_reference, without_reference>;
};

2 つの可能性があります。

  1. コンパイラは、 を見るたびに何らかの作業を行う必要がありtypename std::remove_reference<T>::typeます。中間エイリアスの使用には、ある種の「キャッシング」動作があり、これにより、コンパイラーは一度だけ何らかの作業を行うことができます。

  2. コンパイル時のパフォーマンスは、コンパイラが実行する必要があるテンプレートのインスタンス化の数で測定されます。std::remove_reference<T>::typeは と同じ型を参照するためstd::remove_reference<T>::type、どちらの場合も必要なテンプレートのインスタンス化は 1 つだけであるため、どちらの実装も同等の WRT コンパイル時のパフォーマンスになります。

Bが正しいと思いますが、確認したいと思います。答えがコンパイラ固有のものであることが判明した場合、私は主に Clang と GCC の答えを知りたいと思っています。

編集

テストプログラムのコンパイルをベンチマークして、作業するデータを取得しました。テストプログラムは次のようなことを行います:

template <typename ...> struct result;    

template <typename T>
struct with_cache {
    using without_reference = typename std::remove_reference<T>::type;
    using type = result<without_reference, ..., without_reference>;
};

template <typename T>
struct without_cache {
    using type = result<
        typename std::remove_reference<T>::type,
        ...,
        typename std::remove_reference<T>::type
    >;
{ };

using Result = with[out]_cache<int>::type;

これらは、10,000 個のテンプレート パラメータを使用してプログラムを 10 回コンパイルした平均時間ですresult<>

                -------------------------
                | g++ 4.8 | clang++ 3.2 |
-----------------------------------------
| with cache    | 0.1628s | 0.3036s     |
-----------------------------------------
| without cache | 0.1573s | 0.3785s     |
-----------------------------------------

テスト プログラムは、ここで入手できるスクリプトによって生成されます。

4

1 に答える 1

2

これがすべてのコンパイラーに当てはまるとは言えませんが、GCC、そしておそらく他のすべての主要なコンパイラーはメモ化を使用する予定です。あなたがそれについて考えるならば、それはほとんどそうしなければなりません。

次のコードを検討してください

&f<X, Y>::some_value == &f<X, Y>::some_value

これは true である必要があるため、コンパイラはメソッドと静的メンバーの定義が重複していないことを確認する必要があります。これを行うには他の方法があるかもしれませんが、これは私にメモ化を叫ぶだけです。これを実装する別の方法もわかりません(確かに、私はそれについて非常に一生懸命考えました)

TMP を使用すると、メモ化が発生することが予想されます。そうしないと、遅すぎて本当に苦痛です。コンパイル時のパフォーマンスに大きな違いがあることを確認した唯一の方法は、a) Clang のような高速なコンパイラ (GCC よりも 3 倍高速) を使用し、異なるアルゴリズムを選択することです。小さな定数要素は、私の経験では、C や C++ よりも TMP ではさらに重要ではないように思えます。適切なアルゴリズムを選択し、不必要な作業を行わないようにし、インスタンス化の数を抑えるようにして、優れたコンパイラを使用します (MSVC++ は非常に遅く、C++11 準拠にはほど遠いですが、GCC と Clang は非常に優れています)。本当にできることはこれだけです。

また、より良いコードのためにコンパイル時間を常に犠牲にする必要があります。時期尚早のコンパイル時間の最適化は、単純な時期尚早の最適化よりもはるかに悪いものです。なんらかの理由でパフォーマンスが開発を大幅に妨げた場合、これには例外があるかもしれません。ただ、そのようなケースは聞いたことがありません。

于 2013-06-28T17:55:31.450 に答える