2

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

// Foo.h
class Foo {
    public: template <typename T> void read(T& value);
};

Foo::read<T>変数が宣言されているクラスのコンストラクターにポインターを割り当てると、インスタンス化が発生するようです。

// Foo.cc
#include "Foo.h"

template <typename T>
void Foo::read(T& value) { /* do something */ }

template <typename T> struct Bar {
    Bar<T>() { void (Foo::*funPtr)(T&) = &Foo::read<T>; }
};

static Bar<int  > bar1;
static Bar<long > bar2;
static Bar<float> bar3;

このソリューションは信頼性が高く、移植性があり、標準に準拠していますか? (少なくとも Intel および GNU コンパイラで動作します。)

なぜ単純に使用しないのか疑問に思っている場合は、この質問template Foo::read<int>(int&);を参照してください。

4

3 に答える 3

2

14.7.1 がその場所です。/2 言います:

関数テンプレートの特殊化が明示的にインスタンス化または明示的に特殊化されていない限り、関数テンプレートの特殊化は、関数定義の存在を必要とするコンテキストで特殊化が参照されるときに暗黙的にインスタンス化されます。

関数を呼び出すのと同じように、メンバー関数ポインターを取得するには、関数がプログラムで (おそらく別の TU で) 定義されている必要があります。それが「関数定義が存在する必要がある」という意味だと思うので、これがインスタンス化の原因です。

/9もあります:

実装は、関数テンプレート、メンバー テンプレート、非仮想メンバー関数、メンバー クラス、またはインスタンス化を必要としないクラス テンプレートの静的データ メンバーを暗黙的にインスタンス化してはなりません。

したがって、GCC と Intel がインスタンス化するという事実は、必要のないものは禁止されているため、他のすべての人がインスタンス化する必要があることを示唆しています。もちろん、全員が順応していることが前提です。

于 2011-04-20T10:31:41.207 に答える
2

はい、ソリューションは移植可能です。別の方法はこちら

template <typename T, T> struct user { };
template <typename T> struct Bar {
    typedef user< void (Foo::*)(T&), &Foo::read<T> > user_type;
};

これで、 が暗黙的にインスタンス化されるたびBar<T>に、暗黙的にインスタンス化されますFoo::read<T>。オブジェクトを作成する必要はありません。

于 2011-04-20T16:36:43.890 に答える
1

オブジェクトBar<type>が実際の型で宣言されている場合、間違いなくはい; インスタンス化されますFoo::read<type>()。ただし、その機能のみに限定されます (たとえばFoo::write<type>()、インスタンス化されません)。

他の方法で、次のようなことを試してみると:

template<typename T>
struct X
{
  Bar<T> b1;  // this is required but not sufficient to instantiate Foo::read<T>()
};

その後Foo::read<int>()、宣言するまでインスタンス化されませんX<int>

編集:上記の例では、内部でBar<int> b1;(intの代わりに)を直接宣言し ても十分ではありません。その包含型は、実際の (つまり、非テンプレート) 型でインスタンス化する必要があります。TXX<>

于 2011-04-20T10:20:18.053 に答える