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

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

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

更新

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

我认为当所有模板参数都是显式提供或由默认参数提供时,特化是完全特化,并且完全按照提供的方式用于实例化模板,相反,如果不是所有模板参数,特化也是部分的由于提供一个或多个(但不是全部)的专业化,和/或如果模板参数以由专业化模式修改的形式使用,则需要。例如

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

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<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<>,它就是完全专业化,其他任何东西都是部分专业化。

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

例如,像这样的专业

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

是一个完整的专业化,因为它在类型为bool且 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

作为另一个相当古玩的例子,多参数模板的部分特化可用于完全覆盖主模板

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

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

于 2013-07-10T20:49:07.810 回答