5

次のコンパイルが行われていることに非常に驚いています。

#include <iostream>

using namespace std;

template<typename T>
class SomeCls {
public:
  void UseT(T t) {
    cout << "UseT" << endl;
  }
};

template<>
class SomeCls<int> {
  // No UseT? WTF?!??!?!
};

int main(int argc, char * argv[]) {
  SomeCls<double> d;
  SomeCls<int> i;

  d.UseT(3.14);
  // Uncommenting the next line makes this program uncompilable.
  // i.UseT(100);

  return 0;
}

なぜこれが許可されるのですか?class SomeCls<int>メソッドを必要としないのは間違っているようvoid UseT(T t)です。私はここで専門分野を見逃していると確信しています(私はC ++の専門家ではありません)。誰かが私を教えてくれませんか?

4

4 に答える 4

11

は他のSomeCls<double>タイプとは完全に異なるタイプだからです。それらはまったく関係がないので、好きなメンバーを持つことができます。もちろん、これはコンパイラが文句を言い始める場所です。SomeCls<int>SomeCls<T>i.UseT()

于 2011-06-14T07:07:27.150 に答える
7

スペシャライゼーションは、適切と思われる方法でスペシャライゼーションを作成できます。すべてのメソッドを省略したり、基本クラスを追加または削除したり、データメンバーを追加または削除したりする場合は、それで問題ありません。

template <class T>
class Foo {};

template <>
class Foo<int> { void extrafunc(); }; //fine

template <>
class Foo<bool> : public ExtraBase {}; // fine

template <>
class Foo<double> { int extradata; }; // fine

関数を特殊化する場合、唯一の制限は、引数が(プライマリテンプレートに関して)同じままであるということですが、心ゆくまで過負荷になる可能性があります。

template <class T>
void foo(const T&);

template <>
void foo<int>(int); // not fine, must be const int&

void foo(int); // fine, this is an overload, not a specialisation

template <class T>
void foo(T*); // fine, again this is an overload, not a specialisation
于 2011-06-14T07:02:44.740 に答える
0

コードintがUseTのバージョンを呼び出すことはないため、コードを提供する必要はありません。

于 2011-06-14T07:03:47.110 に答える
0

回答に「正解」のマークを付けましたが、あまり満足していません。私はそれがどのように機能するかを尋ねていません。なぜそのように設計されたのかを尋ねています。それが機能する方法は、OOと一致しているように私を驚かせません。それも一貫しているように見えます。関数テンプレートの特殊化には、インターフェイスが一貫している必要があるという制限があるのに、クラステンプレートの特殊化にはないのはなぜですか?

それがあなたの質問だったなら、あなたはおそらくそもそもそう言うべきだったでしょう。

最後のビットから始めましょう:関数が同一の署名を必要とする理由。それは簡単です。関数には、オーバーロードを介して名前を再利用する方法がすでにあります。

int f(int);
double f(double); //no templates needed

スペシャライゼーションが関数の署名を変更できるようにすると、実際に追加の機能を提供することなく、名前解決のすでに困難なプロセスが不必要に複雑になります。

クラスタイプの場合、テンプレートははるかに複雑です。考慮すべきメンバー関数があるだけでなく、メンバーオブジェクト、typedef、ネストされたタイプなどがあります。スペシャライゼーションはそれらすべてをスペシャライズします。SomeTemplatedObject<double>一般的に必要とされない特定のプライベートメンバーが必要な場合、「インターフェイス」を変更SomeTemplatedObject<T>せずにどのように専門化できますSomeTemplatedObjectか?doubleまたは、特定のタイプに意味をなさないメソッドはどうですか?または、一貫性のあるインターフェイスを維持するために変更する必要があるネストされたタイプですか?そして、それはテンプレートメタプログラミングのより大きな問題にさえ触れていません。

一般的なケースでは、完全なタイプである必要はありません。

template<typename T>
struct Object;

template<>
struct Object<int> { //what interface does this need?
  typedef int type;
};

OOの純粋な定義に固執する必要があると感じた場合は、元のレイアウトと正確に一致させずに、テンプレートを特殊化しないでください。

于 2011-06-15T10:43:33.537 に答える