3

これはC++11でのexternテンプレートの正しい使用法ですか?(extern template classとそれぞれtemplate classが同じ翻訳単位で表示されている可能性がありますか?)

// example.hpp:
#pragma once
template< typename T >
class C {
    void f(T);
};
// question is about the next two lines
extern template class C< float >;
extern template class C< double >;
// example_def.hpp:
#include "example.hpp"
template< typename T >
void C< T >::f(T) {
    //... smth. practicable
}
// example.cpp:
#include "example_def.hpp"
template class C< float >;
template class C< double >;
// other.hpp:
#pragma once
void g();
// other.cpp:
#include "other.hpp"
#include "example.hpp"
// maybe those two lines should be here instead?
void g() {
    C< float >();
    C< double >();
}
// main.cpp:
#include "example.hpp"
#include "other.hpp"
// ...and here?
int main() {
    C< float >();
    C< double >();
    g();
    return 0;
}
4

2 に答える 2

4

はい、定義 ( なし) が宣言 ( あり) の後に続く場合、仕様 (標準では明示的インスタンス化宣言extern template classと呼ばれます) と仕様 (標準では明示的インスタンス化定義と呼ばれます) の両方を同じ翻訳単位にすることができます。template classexternextern

(§14.7.2/11)エンティティが、同じ翻訳単位内の明示的なインスタンス化宣言と明示的なインスタンス化定義の両方の対象である場合、定義は宣言に従うものとします。明示的なインスタンス化宣言の対象であり、翻訳単位で暗黙的なインスタンス化 (14.7.1) を引き起こす方法でも使用されるエンティティは、プログラムのどこかで明示的なインスタンス化定義の対象となります。それ以外の場合、プログラムは不正な形式であり、診断は必要ありません。[注: この規則はインライン関数にも適用されますが、そのようなエンティティの明示的なインスタンス化宣言には他の規範的な効果がありません。これは、インライン関数のアドレスが、実装が行外の本文を抑制することを選択した翻訳単位で取得された場合に、別の翻訳単位が本文を提供することを保証するために必要です。— 終わりの注 ] 明示的なインスタンス化宣言は、内部リンケージを持つテンプレートの特殊化を指定してはなりません。

(強調鉱山)。明示的インスタンス化宣言明示的インスタンス化定義という用語は、次のように定義されています。

(§14.7.2/2) 明示的なインスタンス化の構文は次のとおりです。

明示的なインスタンス化:
externopt template 宣言

明示的なインスタンス化には、明示的なインスタンス化の定義と明示的なインスタンス化の宣言の 2 つの形式があります。明示的なインスタンス化宣言は、extern キーワードで始まります。


これらの明示的なインスタンス化の効果は次のとおりです。

  1. 明示的なインスタンス化宣言 ( with ) は、すべての暗黙的externなインスタンス化が有効になるのを防ぎます(インライン関数とクラス テンプレートの特殊化、§14.7.2/10 を除く)。

  2. 明示的なインスタンス化の定義 ( なしextern) は、インスタンス化を何があっても発生させます。つまり、明示的なインスタンス化の宣言をオーバーライドします (これも §14.7.2/10 に従います)。


一般的なコメント
明示的なインスタンス化宣言がテンプレートを定義するヘッダー ファイルに配置されているという事実は、テンプレートを利用するためにヘッダー ファイルをインクルードする人は、明示的なインスタンス化定義も追加する必要があることを意味します。.cppそのような明示的なインスタンス化定義を含む別のファイルのコードにリンクする必要があります。

これは混乱を招く可能性があり、多くの異なるユーザーが多くの異なるタイプのテンプレートをインスタンス化することが予想される場合、おそらくあまり良い考えではありません。ただし、個別の型のインスタンス化の数が少なく、それらすべてを予測できる場合は賢明です。もちろん、必要なすべてのインスタンス化の.cpp明示的なインスタンス化定義を含む 1 つ (または複数) のファイルが存在し、それに対応するオブジェクト ファイルがビルド時にプロジェクトにリンクされていることを確認する必要があります。

于 2012-12-24T12:23:40.427 に答える
3

テンプレートの基本的な考え方はextern、一般的に使用されるインスタンス化の明示的なインスタンス化をサポートすると同時に、あまり一般的に使用されないパラメーターの暗黙的なインスタンス化もサポートすることです。たとえば、std::basic_string<char>明示std::basic_string<signed char>的にインスタンス化することはできますが、暗黙的なインスタンス化のために残すことができます(実際の動機付けの例は、インスタンス化されるのにかなりの時間がかかるIOStreamですが、実際には2つのインスタンス化のみが使用されます)。

暗黙的なインスタンス化を可能にするには、使用されているテンプレートの定義が、テンプレートが使用されている各翻訳単位で表示される必要があります。テンプレート定義が表示されている場合、コンパイラーはデフォルトでインスタンス化を暗黙的に提供する必要があると想定します。テンプレート宣言を使用するexternと、特定のテンプレートのインスタンス化が何らかの変換ユニットによって提供されることをコンパイラーに通知します。

ケースは機能しますが、テンプレートを宣言する必要はありませexternん。コンパイラがインスタンス化を使用し、その定義が見つからない場合、インスタンス化が何らかの翻訳単位で見つかったと見なされます。

于 2012-12-24T13:02:44.593 に答える