8

テンプレート クラス List があります。

template <typename Point>
class List
{


    public:
          template <const unsigned short N>
          void load ( const char *file);
          ...
};

template <typename Point>
template <const unsigned short N>
void List <Point>::load ( const char *file)
}

N=2 のメソッド ロードを特殊化する方法は? このコードは無効です...

template <typename Point>
void List <Point> <2>::load ( const char *file)
{
}

また、このコードも機能しません。

template <typename Point>
void List <Point> ::load <2> ( const char *file )
{ 
}

Error 3 error C2768: 'List<Point>::load' : illegal use of explicit template arguments 66. 
Error 5 error C2244: 'List<Point>::load' : unable to match function definition to an existing declaration 66

コンパイラ g++:

template <typename Point>
template <>
void List <Point> ::load <2> ( const char *file )
{
}

error: explicit specialization in non-namespace scope `class List<>'
error: enclosing class templates are not explicitly specialized
error: default arguments are only permitted for function parameters
error: `load' is not a function template
error: invalid function declaration
4

3 に答える 3

9

C++ 仕様には、外側のテンプレートも明示的に特殊化しない限り、テンプレート クラスまたはテンプレート クラス内にネストされた関数の特殊化を明示的に禁止する条項があることがわかりました。Visual Studio はこの規則を強制しないため、前の例と混乱しますが、g++ は確かに強制します。

テンプレートを特殊化する場合は、外側のテンプレートも特殊化するか、テンプレート パラメーターに基づいて 2 つの異なる実装のいずれかにメソッドをディスパッチすることで特殊化の動作を偽造するかのいずれかを選択できます。どちらもあまり満足のいくものではありませんが、残念なことに、言語はいくつかのテンプレート コーナーで奇妙に設計されています。:-(

明示的な特殊化の動作をエミュレートできる 1 つの方法は、タグ ディスパッチと呼ばれる手法を使用することです。アイデアは、次のような非常に単純な構造体を作成することです。

template <unsigned short N> struct Box {};

このタイプは完全に空です。直接使用することを意図したものではなく、整数を型システムに埋め込む方法にすぎません。特に、はなどBox<3>と同じ型ではありません。Box<4>

次に、リスト クラスで、次のような 2 つの関数を定義します。

template <unsigned short N>
    void doLoad(const char* file, Box<N>);
void doLoad(const char* file, Box<2>);

これら 2 つの関数は互いのオーバーロードであり、最後のパラメーター (Box<N>テンプレートの場合は a またはBox<2>非テンプレートの場合は a) によってのみ区別できます。パラメータには名前がないことに注意してください。これは恣意的な決定ですが、実際にパラメーターを読み取る予定はないため、パラメーターは必要ありません。これらの関数の背後にある直感は、この最初の関数が 2 以外のすべてに対して機能する「キャッチオール」実装になるということですN。2 番目のバージョンには、N == 2.

最後に、次のように実装loadします。

template <typename Point>
    template <unsigned short N>
void List<Point>::load(const char* file) {
    doLoad(file, Box<N>());
}

これはどのように作動しますか?この関数はパラメーターを受け取り、doLoadそのパラメーターを最初の引数として転送しBox<N>、2 番目の引数として一時を渡します。が 2 でない場合、これは、キャッチオール ハンドラであるNのテンプレート バージョンへの呼び出しです。doLoad一方、が 2 の場合、オーバーロードの解決中に非テンプレート関数がテンプレート関数よりも優先されるため、Nこれは の非テンプレート バージョンを呼び出します。doLoad

要するに、の実装はloadトランポリンになり、2 つの実装のうち正しい方に進むことができます。次に、ロジックを適切なdoLoad関数に配置して、必要な動作を得ることができます。

お役に立てれば!

于 2011-02-09T22:02:16.377 に答える
1

編集:わかりましたので、インライン関数定義を使用してクラスを少し書き直しましたが、これは間違いなく機能します:

template <typename Point>
class List
{
public:
    template <const unsigned short N>
    void load( const char *file){
    }

    template<>
    void load<2>(const char* file){
    }
};
于 2011-02-09T11:29:46.260 に答える
1

クラス テンプレートを特殊化せずにメンバー テンプレートを特殊化することはできません。

また、関数パラメーターで使用されていないため、N の意味は何なのだろうか?

于 2011-02-09T22:03:18.090 に答える