11

次のヘッダーとソース ファイルを検討してください。

// main.cpp
#include "myClass.h"

int main()
{
  MyClass m;
  m.foo<double>();
  m.foo<float>();
}

// myClass.h
#pragma once

#include <iostream>

using namespace std;

class MyClass
{
public:

  template <typename T>
  void foo()
  {
    cout << "Template function<T> called" << endl;
  }

  template <>
  void foo<int>()
  {
    cout << "Template function<int> called" << endl;
  }

  template <>
  void foo<float>();

};

// myClass.cpp
#include "myClass.h"

template <>
void MyClass::foo<float>()
{
  cout << "Template function<float> called" << endl;
}

foo<float>特殊化に関してリンクエラーが発生します。特殊化の定義をヘッダー ファイルに配置すると、すべてが期待どおりに機能します。

その理由は、メソッドが明示的にインスタンス化されていないためである可能性があると考えました(ただし、完全な特殊template class化では、適切なリンクのために明示的なインスタンス化は必要ありません)。メソッドを明示的にインスタンス化しようとすると、次のエラーが発生します。

エラー C3416: 'MyClass::foo': 明示的な特殊化は明示的にインスタンス化されていない可能性があります

質問は次のとおりです。

  • ファイルに特殊化を定義してcpp適切にリンクする方法はありますか?
  • そうでない場合、なぜですか?特殊化されていないテンプレート メソッドを明示的にインスタンス化できます。完全なスペシャライゼーションで同じではないのはなぜですか?
4

1 に答える 1

17

WhozCraig の回答 (現在は削除されています) は、問題を解決するための正しいコードを提供しますが、コードに関するコメントを含む、質問に対する直接的な回答をいくつか示します。

  1. foo<int>()およびfoo<float>()メンバー テンプレートの明示的な特殊化です。それらは、それらが属するクラスの定義内に現れてはなりません。規格は次のように述べています。

    (§14.7.3/3) [...] クラスまたはクラス テンプレートの定義は、クラスまたはクラス テンプレートのメンバー テンプレートの明示的な特殊化の宣言に先行するものとします。[...]

    したがって、クラス定義の後に配置する必要があります。

  2. ヘッダー ファイルで完全に定義されている の場合foo<int>、これは定義のinline前に単語を配置する必要があることを意味します。そうしないと、ヘッダー ファイルが複数の翻訳単位に含まれている場合に、リンカーで問題が発生します。

  3. の特殊化foo<float>()は、後で にリンクされる別のファイルで定義されますmain.cpp。これは可能ですが、ヘッダー ファイルで宣言する必要があります (これは既に行っていますが、クラス定義の外で行う必要があります)。

      template <>
      void MyClass::foo<float>();
    

    これは、標準の別のステートメントのために必要です。

    (§14.7.3/6) テンプレート、メンバー テンプレート、またはクラス テンプレートのメンバーが明示的に特殊化されている場合、その特殊化は、暗黙的なインスタンス化を発生させる特殊化の最初の使用の前に宣言する必要があります。そのような使用が発生する翻訳単位。診断は必要ありません。[...]

  4. すべての特殊化は明示的であるため(つまり、あなたの言葉を使用するために完全な特殊化)、明示的なインスタンス化の必要はありませんが、可能です (§14.7.2)。それらを .cpp ファイルの末尾に配置すると、構文は次のようになります。

    template void MyClass::foo<float>();
    template void MyClass::foo<int>();
    

    繰り返しますが、これは、独自の明示的な特殊化を持たない型に対してのみ本当に役立ちます。

したがって、ヘッダーと実装ファイルの正しいコードは次のようになります。

.h ファイル:

class MyClass
{
public:
  template <typename T> void foo()
  { cout << "Template function<T> called" << endl; }
};

template <> inline void MyClass::foo<int>()
{ cout << "Template function<int> called" << endl; }

template <> void MyClass::foo<float>();

.cpp:

#include "myClass.h"

template <> void MyClass::foo<float>()
{ cout << "Template function<float> called" << endl; }

/* This is unnecessary for float, but may be useful for
   types that do not have their own explicit specializations: */
template void MyClass::foo<float>();
于 2012-12-29T07:02:17.937 に答える