5

テンプレートベースのクラス(STLおよびブースト)にソースファイルを使用せず、実装をヘッダーに配置することも一般的な慣習のようです。これにより、ヘッダーとソースファイルでの宣言と実装の従来の分離と比較して、ヘッダーを含むソースファイルのコンパイルにかかる時間が大幅に増えると思います。これが行われる理由は、おそらく、ソースファイルでコンパイラに使用するテンプレートを指示する必要があるためです。これにより、.aファイルが肥大化する可能性があります。

ライブラリが大きくなるにつれてリンカーもより多くの時間を必要とすると仮定すると、ライブラリヘッダーを含むソースファイルのコンパイルにかかる時間の観点から、どちらのアプローチがより高速になりますか?

1. .cppファイルを使用せず、実装を含むクラス全体をヘッダーに配置します

//foo.hpp
template <class T>
class Foo
{
public:
    Foo(){};
    T bar()
    {
        T* t = NULL;
        //do stuff
        return *t;
    }
};

また

2.ライブラリ自体のソースファイル内でさまざまなタイプのテンプレートを明示的にコンパイルします

//foo.h
template <class T>
class Foo
{
public:
    Foo(){};
    T bar();
};

//foo.cpp
template <class T>
T Foo<T>::bar()
{
    T* t = NULL;
    //do stuff
    return *t;
}

template class Foo<int>;
template class Foo<float>;
template class Foo<double>;
template class Foo<long long>;
4

3 に答える 3

4

通常、コンパイラは特定のコンパイルユニットに対して1回コードを生成し、リンカは他のコンパイルユニットが変数と関数にアクセスできるようにします。

テンプレートに関しては、これはもはや当てはまりません。テンプレートの具体的なインスタンスがインスタンス化される前に、コンパイラはテンプレートのコードを生成できません。したがって、すべてのコンパイルユニットでテンプレートをインスタンス化します。コピーアンドペーストせずにこれを行う唯一の方法は、すべてのテンプレートコードをヘッダーファイルに配置することです。

リンカは、テンプレートを認識し、同じオブジェクトの複数のインスタンスを調整する必要もあります。

C ++ 11は、次のように宣言できるこのシナリオで少し役立ちます。

template class MyTemplate<MyType>;

単一のC++ファイルで、次を使用します。

extern template class MyTemplate<MyType>;

後者は、現在のコンパイルユニットでテンプレートをインスタンス化しませんが、リンカがすでに定義されているものにリンクするようにします。

詳細については、こちらをご覧ください

于 2012-10-16T15:34:50.577 に答える
4

テンプレートの重要な問題は、コンパイラがテンプレートが使用されるテンプレート引数を認識しないことです。テンプレートが特定の引数のセットで使用されていることをコンパイラーが認識しているのは、使用されているテンプレートを確認したときだけであり、コンパイラーはこの時点でテンプレートをインスタンス化します。その結果、コードはヘッダーに挿入されることが多く、コンパイラーは、使用時にユーザーに代わってテンプレートをインスタンス化できます。

あるいは、テンプレートの作成者は、テンプレートがテンプレート引数の特定のリストで使用されていることをコンパイラーに通知し、それらを明示的にインスタンス化することができます。この場合、テンプレート定義はソースファイル(または、通常はユーザーに含まれない特別なヘッダー)に入れることができます。このアプローチの問題は、テンプレートコードの作成者が、どのインスタンス化が必要かを必ずしも知らないことです。

C ++ 2011には、中間点もあります。特殊化をとして宣言することにより、特定のインスタンス化がすでに作成されていることをコンパイラーに通知することができますextern。このように、コンパイラは、特定の引数を使用してテンプレートをインスタンス化する必要がないことを認識していますが、他の引数が使用されている場合は、それらを作成する必要があることを認識しています。たとえば、標準C ++ライブラリにはがあり、のインスタンス化が使用される可能性が高いstd::basic_stringことを予測し、それらをライブラリに入れて、インスタンス化をとして宣言できます。ただし、コードをすぐに利用できるようにすると、ユーザー定義の型で使用できるようになります。charwchar_texternstd::basic_string<user_type>

将来的にはモジュールシステムを手に入れたいと思っていますが、今のところ、そのようなシステムが実際にどのように機能するかは誰にもわかりません。このトピックに関心のあるコンパイラ実装者には、モジュールについて考えるグループがあり、このようなシステムがテンプレートのコンパイル時間に役立つ可能性があります。

于 2012-10-16T15:48:47.587 に答える
1

すでに2つの良い答えがあるので、簡単に書きます。
テンプレート化されたコードは、具体的な型がないとコンパイルできません。そのため、従来の「コンパイルとリンク」を実行することはできません。
テンプレート関数またはクラスは、コード内の特定の使用法(特定のタイプがテンプレートを置き換える場合)まで、すべてのタイプが解決されるわけではないという意味で、完全ではありません。
このため、テンプレートはヘッダーファイルに配置され、特定の使用法に関係なくコンパイルすることはできません。

于 2012-10-16T15:58:28.370 に答える