2

テンプレート化されたメンバー関数について少し混乱しています。次のようなテンプレート化されたメンバー関数を持つ奇妙な構造体があるとしましょう。

struct Foo
{
    template <typename T> void f(T t) {};
};

次に、その構造体をいくつかの標準コンテナに格納します。

std::vector<Foo> V;

V.push_back(Foo());
V.push_back(Foo());
V.push_back(Foo());
V.push_back(Foo());

次; テンプレート化されたメンバー関数のさまざまなインスタンスを呼び出しましょう。

V.at(0).f<int>(1);
V.at(0).f<char>(2);
V.at(1).f<float>(3.4f);
V.at(2).f<double>(5.6);
V.at(3).f<long>(7);

そして最後に、質問:

¿Fooクラスのすべてのインスタンスは同じクラスからのものですか?答えはイエスのようですが...最初のFooインスタンスには、最後にfメンバー関数の2つのオーバーロードがあります。

[0] Foo::f(int t);
[0] Foo::f(char t);

一方、他のFooインスタンスには、f関数のバージョンが1つしかないようです。そのため、メンバー関数の違いにより、各インスタンスの基本タイプが異なるようです。

[1] Foo::f(float t);
[2] Foo::f(double t);
[3] Foo::f(long t);

¿f関数はどこにインスタンス化されますか?Foo :: f(int t)関数のアドレスは、最初のFooインスタンスからのみ取得できるようです。これは、その関数がそのインスタンスにのみ属しているためです。他の機能についても同じです。

前もって感謝します。

4

4 に答える 4

7

すべてのオーバーロードは、Foo::fメンバー関数用にコンパイラーによって生成されます。これは、すべてを手動で書き出したものと考えることができます。

オーバーロードの生成(テンプレートのインスタンス化)はインスタンスベースではなく、クラスベースであり、クラス自体がすべてのテンプレートのインスタンス化をスプラットします(与えられたクラスの本体にさまざまなタイプのすべてのオーバーロードを書き込んだように)タイプT)

だからこれはあなたの場合:

struct Foo 
{     
   template <typename T> void f(T t) {}; 
}; 

(概念的に)になるだろう

struct Foo 
{     
   void f<int>(int t) {}; 
   void f<char>(char t) {}; 
   void f<float>(float t) {}; 
   ...
   /// all the other uses of f with different types, anywhere in your code.
}; 

これは、人々がテンプレートに反対する理由の1つであり、「コード膨張」と呼ばれます。

于 2012-06-20T14:37:18.800 に答える
1

¿Fooクラスのすべてのインスタンスは同じクラスからのものですか?答えはイエスのようです

はい、すべてのインスタンスは同じタイプです。

しかし...最初のFooインスタンスには、最後にfメンバー関数の2つのオーバーロードがあります

オーバーロードは、インスタンスごとではなく、タイプごとです。テンプレート関数がインスタンス化されたオブジェクトに関係なく、タイプにはすべてのオーバーロードが含まれます。

¿f関数はどこにインスタンス化されますか?Foo :: f(int t)関数のアドレスは、最初のFooインスタンスからのみ取得できるようです。これは、その関数がそのインスタンスにのみ属しているためです。他の機能についても同じです。

それらはコンパイラによってインスタンス化(バイナリコードにコンパイル)されますが、これは適切な質問ではありません(バイナリ以外)。メンバー関数のアドレスはクラスからのみ取得でき、インスタンスからは取得できません。すでに述べたように、メンバー関数はタイプごとであり、タイプごとのインスタンスではありません。

于 2012-06-20T14:39:29.377 に答える
0

すべてのFooインスタンスにはすべてのオーバーロードがあり、Fooそれ自体はテンプレートクラスではないため、すべて同じタイプです。

関数は、コンパイル時にオブジェクトコードでインスタンス化されます。

于 2012-06-20T14:38:25.977 に答える
0

別の例を見てみましょう。

struct Foo
{
    void f(int);
    void f(double);
};

// ...
Foo foo1, foo2;
foo1.f(3);
foo2.f(3.0);

これは、コンパイラがメソッドの新しいインスタンス化を作成しないことを除いて、独自のバージョンと完全に類似していますf()。でメソッドf(int)を呼び出すだけで、。でメソッドをfoo1呼び出すだけです。すべてのインスタンスですべてのメソッドを呼び出すわけではないという理由だけで、それらは現在異なるタイプになっていると思いますか?f(double)foo2

メソッドは、インスタンスではなく、クラスに関連付けられています。コードが生成するすべてのメソッドオーバーロードはクラスのメソッドでありFoo、すべてのインスタンスは同じタイプです。

于 2012-06-20T14:40:11.040 に答える