4

これは、VS2012 に同梱されている C++ 標準ライブラリの xutility ヘッダーからのものです。

template<class _Elem1,
    class _Elem2>
    struct _Ptr_cat_helper
    {   // determines pointer category, nonscalar by default
    typedef _Nonscalar_ptr_iterator_tag type;
    };

template<class _Elem>
    struct _Ptr_cat_helper<_Elem, _Elem>
    {   // determines pointer category, common type
    typedef typename _If<is_scalar<_Elem>::value,
        _Scalar_ptr_iterator_tag,
        _Nonscalar_ptr_iterator_tag>::type type;
    };

具体的には、2 番目の _Ptr_cat_helper 宣言の性質は何ですか? 宣言子 _Ptr_cat_helper の後の山括弧は、特殊化のように見せます。ただし、テンプレートを特殊化するために完全または部分的な型を指定する代わりに、テンプレート引数を複数回繰り返すだけです。

私は前にそれを見たことはないと思います。それは何ですか?

アップデート

両方のテンプレート引数が同じ型であるテンプレートのインスタンス化に特殊化が適用されることは明らかですが、これが完全な特殊化を構成するのか部分的な特殊化を構成するのか、またはその理由については明確ではありません。

すべてのテンプレート引数が明示的に提供されるか、デフォルトの引数によって提供され、テンプレートをインスタンス化するために提供されたとおりに使用される場合、特殊化は完全な特殊化であり、逆に、すべてのテンプレートパラメーターではないにしても、特殊化は部分的であると考えましたそれらの 1 つまたは複数 (すべてではない) を提供する特殊化のために、および/またはテンプレート引数が特殊化パターンによって変更された形式で使用された場合に必要でした。例えば

特殊化がテンプレート引数のすべてではなく少なくとも 1 つを提供しているため、部分的な特殊化。

template<typename T, typename U>
class G { public: T Foo(T a, U b){ return a + b; }};

template<typename T>
class G<T, bool> { public: T Foo(T a, bool b){ return b ? ++a : a; }};

特殊化により、指定されたテンプレート引数が部分的にしか使用されないため、部分的な特殊化。

template<typename T>
class F { public: T Foo(T a){ return ++a; }};

template<typename T>
class F<T*> { public: T Foo(T* a){ return ++*a; }};

この 2 番目の例では、テンプレートが A<char*> を使用してインスタンス化された場合、テンプレート内の T は実際には char 型になります。つまり、指定されたテンプレート引数は、特殊化パターンの適用により部分的にしか使用されません。

それが正しい場合、元の質問のテンプレートは部分的な専門化ではなく完全な専門化にはなりません。そうでない場合、私の誤解はどこにありますか?

4

2 に答える 2

11

これは、両方のパラメーターに同じ型が渡される場合の部分的なクラス テンプレートの特殊化です。

多分これは読みやすいでしょう:

template<typename T, typename U>
struct is_same : std::false_type {};

template<typename T>
struct is_same<T,T> : std::true_type {};

編集:

特殊化が明示的な (完全な) 特殊化なのか、部分的な特殊化なのか不明な場合は、この問題について非常に明確な標準を参照できます。

n3337、14.7.3./1

次のいずれかの明示的な特殊化:

[...]

によって導入された宣言によって宣言できますtemplate<>。あれは:

明示的な専門化:宣言
template < >

および n3337、14.5.5/1

プライマリ クラス テンプレート宣言は、クラス テンプレート名が識別子である宣言です。クラス テンプレート名がsimple-template-idであるテンプレート宣言は、simple-template-idで指定されたクラス テンプレートの部分的な特殊化です。[...]

simple -template-idは文法で次のように定義されています。

単純なテンプレート ID:

テンプレート名 < テンプレート引数リストの選択 >

テンプレート名

識別子

したがって、 があるところはどこでもtemplate<>、それは完全な特殊化であり、それ以外はすべて部分的な特殊化です。

次のように考えることもできます。完全なテンプレートの特殊化は、プライマリ テンプレートの可能なインスタンス化を1 つだけに特化します。それ以外は部分的な専門化です。あなたの質問の例は部分的な特殊化です。これは、引数を同じ型に制限する一方で、テンプレートをインスタンス化できる無限に多くの異なる引数を許可するためです。

たとえば、このような専門分野

template<>
vector<bool> { /* ... */ };

タイプがbooland onlyの場合に機能するため、完全な特殊化boolです。

それが役立つことを願っています。


そして、言及する価値があると思うメモです。すでにご存知だと思いますが、関数テンプレートは部分的に特化することはできません。この間

template<typename T>
void foo(T);

template<typename T>
void foo(T*);

foo一見すると for ポインターの部分的な特殊化のように見えるかもしれませんが、そうではありません。オーバーロードです。

于 2013-07-10T20:35:37.047 に答える
5

テンプレートの特殊化を実行するときに「完全な型または部分的な型」を指定することに言及しています。これは、クラステンプレートの部分的な特殊化などの言語機能を認識していることを示唆しています。

部分的な特殊化には、かなり広範な機能があります。一部のテンプレート パラメーターに具体的な引数を指定するだけに限定されません。また、次の例のように、cv 修飾または間接レベルに基づいて、引数の型の特定のグループに対して専用のバージョンのテンプレートを定義することもできます。

template <typename A, typename B> struct S {}; 
// Main template

template <typename A, typename B> struct S<A *, B *> {}; 
// Specialization for two pointer types

template <typename A, typename B> struct S<const A, volatile B> {}; 
// Specialization for const-qualified type `A` and volatile-qualified type `B`

また、一部のテンプレート引数が同一か異なるかに基づいた特殊化もカバーしています。

template <typename A> struct S<A, A> {}; 
// Specialization for two identical arguments

template <typename A> struct S<A, A *> {}; 
// Specialization for when the second type is a pointer to the first one

もう 1 つの興味深い例として、複数引数テンプレートの部分的な特殊化を使用して、メイン テンプレートを完全にオーバーライドできます。

template <typename A, typename B> struct S<B, A> {}; 
// Specialization for all arguments

コード サンプルに戻ると、2 つの同一の引数の部分的な特殊化は、投稿したコードで使用されているものとまったく同じです。

于 2013-07-10T20:49:07.810 に答える