2013-01-04 14 views
5

はなぜ明示的なテンプレートのインスタンスの位置が問題

#include "a.h" 

template<bool b> 
void A<b>::print(std::ostream& out) { 
    out << "A" << b; 
} 

template class A<true>; 
template class A<false>; 

私はA

a.h
#include <iostream> 

template<bool b> 
class A { 
public: 
    void print(std::ostream& out); 
}; 

テンプレートクラスを宣言し、(truefalseの明示的なinstatiationで)a.cppに印刷する方法を定義します言うんmain.cppの主なメインプログラムの例は、

#include "a.h" 

int main() { 
    A<true> a; 
    a.print(std::cout); 
} 

上記の小さなプロジェクトはうまくコンパイルされます。

質問:私は(a.cpp中)printメソッドの定義上記の明示的なインスタンス化を入れた場合、コードは通常のundefined reference to A<true>::print(...)エラーで、もうコンパイルされません。

#include "a.h" 

template class A<true>; 
template class A<false>; 

template<bool b> 
void A<b>::print(std::ostream& out) { 
    out << "A" << b; 
} 

なぜこの場合ですか?

編集:Makefileはコンパイルする

main : main.o a.o 
    g++ main.o a.o -o main 

main.o : main.cpp 
    g++ -c main.cpp 

a.o : a.cpp 
    g++ -c a.cpp 
+1

もVS2012で動作します。 – billz

+0

私はして、Dejanが述べたように注文を変更しました – billz

+1

@jogojapan - +1。 clang32とgcc48でコンパイルしたという私のコメントを削除しました。私が最初にテストしたように、3つのファイルの内容を1つのファイルにカットアンドペーストした場合、どのコンパイラでも問題なくコンパイルできました。 DejanがMakefileを投稿した後、私はあらゆるバージョンのclangとgccでエラーを再現できました。 –

答えて

8

私は良いとは思わないでしょうナチュラルなぜそうですか?コンパイラは明示的なインスタンス化–の後に同じファイル内にあるために提供されていても、メンバ関数の定義を見ることができます。

ただし、コンパイラはこれに必須ではありません。それは実際には明示的に標準によって禁止です:

(§14.7.2/ 9)クラステンプレートの特殊化が明示的にクラステンプレートの特殊化をインスタンス化し、メンバーのみの明示的なインスタンスの定義で名前明示的なインスタンスの定義インスタンス化の時点で定義されています。

私はこの理由には次のものが含ま推測:

  • 以降の翻訳単位でのメンバ関数の一部のためにいくつかの明確な明示的な特殊化があるかもしれません。プログラマの興味の中でも、これらのどれがインスタンス化されるかについての明確なルールを持つことは意味があります。

  • テンプレートがで暗黙的にがインスタンス化されると、インスタンス化のポイントより前に定義された特殊化のみが考慮されます。したがって、暗黙的および明示的なインスタンス化のルールは同じです。

1
template class A<true>; 
template class A<false>; 

テンプレートコードはヘッダ自体に定義されていること、それは、典型的に期待される理由同じ理由。明示的なインスタンス化を実行するには、のテンプレートクラスの定義全体を参照できるようにする必要があります(main.cppからは不可能です)。

しかし、a.cppは、クラスのすべての定義(ここではprintメソッド)にアクセスできるため、明示的なインスタンス生成が可能です。

+0

私はあなたの答えを理解するか分からない。私の混乱は、 'a.cpp'内のステートメントの並べ替えにあります。 –

+0

@DejanJovanović:ああ、私の勘違いは、コンパイラのように見えますが、VS2010で動作します –