这个模板构造是什么?

时间:2013-07-10 20:27:37

标签: c++ template-specialization

这是来自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;
    };

具体来说,第二个_Ptr_cat_helper声明的性质是什么?声明符_Ptr_cat_helper之后的尖括号使它看起来像一个特化。但是,不是指定专门用于模板的完整或部分类型,而是多次重复模板参数。

我认为我以前没见过。它是什么?

更新

我们都很清楚,专业化适用于模板的实例化,其中两个模板参数的类型相同,但我不清楚这是构成完全或部分特化,还是为什么。

我认为当所有模板参数显式提供或由默认参数提供时,专门化是完全特化,并且完全用于提供实例化模板,相反,如果不是全部,则专业化也是部分的由于提供了一个或多个(但不是全部)的特化,并且/或者模板参数是在由特化模式修改的形式中使用的,因此需要模板参数。 E.g。

部分专业化,因为专业化提供至少一个但不是全部的模板参数。

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; }};

在第二个示例中,如果使用A&lt; char *&gt;实例化模板然后模板中的T实际上是char类型,即由于应用了特化模式,所提供的模板参数仅部分使用。

如果这是正确的,那么不会使原始问题中的模板成为完全专业化而不是部分专业化,如果不是这样,那么我的误解在哪里?

2 个答案:

答案 0 :(得分: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-name&lt; template-argument-list opt&gt;

  
     

模板名称

     
    

标识符

  

所以,无论哪里有template<>,它都是完全专业化,其他任何东西都是部分专业化。

您也可以这样考虑:完全模板专门化专门用于主要模板的一个可能的实例化。其他任何东西都是部分专业化。您的问题中的示例是部分特化,因为虽然它将参数限制为相同类型,但它仍然允许模板可以实例化的无限多个不同参数。

像这样的专业化,例如

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

是一个完整的专业化,因为它在类型为bool且仅bool时启动。

希望有所帮助。


只是一张纸条,我觉得值得一提。我想你已经知道了 - 功能模板不能局部专业化。虽然这个

template<typename T>
void foo(T);

template<typename T>
void foo(T*);
对于乍一看指针,

可能看起来像是foo的部分特化,它不是 - 它是一个过载。

答案 1 :(得分: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

另一个相当古怪的例子,多参数模板的部分特化可以用来完全覆盖主模板

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

现在,返回到您的代码示例,两个相同参数的部分特化正是您发布的代码中使用的内容。