3

次のコードをコンパイルすると、次のようになります。

//
// g++ static.cpp -o static.o
// ar rcs libstatic.a static.o
//
#include <iostream>

template < typename T >
struct TemplatedClass
{
  void Test( T value )
  {
    std::cout << "Foobar was: " << value << std::endl;
  }
};

template struct TemplatedClass < long >;

静的ライブラリを取得し、ライブラリでnmを実行すると、次の結果が得られます。

testcase% nm libstatic.a | c++filt | grep TemplatedClass
0000000000000207 s global constructors keyed to _ZN14TemplatedClassIlE4TestEl
0000000000000300 s global constructors keyed to _ZN14TemplatedClassIlE4TestEl.eh
0000000000000118 T TemplatedClass<long>::Test(long)
00000000000002a0 S __ZN14TemplatedClassIlE4TestEl.eh

ただし、次のコードをコンパイルすると、テンプレートクラスの明示的な特殊化を追加したことを除いて同じです...

//
// g++ static.cpp -o static.o
// ar rcs libstatic.a static.o
//
#include <iostream>

template < typename T >
struct TemplatedClass
{
  void Test( T value )
  {
    std::cout << "Foobar was: " << value << std::endl;
  }
};

template <>
struct TemplatedClass < long >
{
  void Test( long value )
  {
     std::cout << "Value was: " << value << std::endl;
  }
}; 

template struct TemplatedClass < long >;

...そして同じコマンドを再実行します:

testcase% nm libstatic.a | c++filt| grep TemplatedClass
testcase% 

一致する記号がありません。どういうわけか、私が明示的に要求したにもかかわらず、コンパイラーはテンプレートをインスタンス化しません。

誰かがここで何が起こっているのか私に説明できますか?

4

1 に答える 1

6

クラス(テンプレート)定義内にメンバー関数定義があります。これにより、メンバー関数(テンプレート)はになりますinline。テンプレートクラスのメンバー関数では、そのリンケージ要件はインスタンス化の性質によって決定されるため、これはそれほど重要ではありません。

ただし、2番目の例では、メンバー関数void TemplatedClass<long>::Test(long)は関数テンプレートではなく、まだinlineです。したがって、コンパイラは、使用されない限り、コンパイラで何もする必要はなく、使用されるすべてのファイルで定義する必要があります。これはstatic.cppファイルにあると主張しているので、インライン関数はおそらくあなたが望むものではありません。

次のように変更すると、期待どおりの結果が得られると思います。

template <>
struct TemplatedClass < long >
{
  void Test( long value );
};

void TemplatedClass<long>::Test( long value )
{
  std::cout << "Value was: " << value << std::endl;
}

And when you define an explicit specialization, you probably don't also need an explicit instantiation (if that's even legal).

于 2010-10-21T16:46:29.583 に答える