Neutrino
Neutrino

Reputation: 9686

What is this template construct?

This is from the C++ Standard Library xutility header that ships with VS2012.

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

Specifically what is the nature of the second _Ptr_cat_helper declaration? The angle brackets after the declarator _Ptr_cat_helper make it look like a specialization. But instead of specifying full or partial types by which to specialize the template it instead just repeats the template argument multiple times.

I don't think I've seen that before. What is it?

UPDATE

We are all clear that the specialization applies to an instantiation of the template where both template arguments are of the same type, but I'm not clear on whether this constitutes a full or a partial specialization, or why.

I thought a specialization was a full specialization when all the template arguments are either explicitly supplied or are supplied by default arguments, and are used exactly as supplied to instantiate the template, and that conversely a specialization was partial either, if not all the template parameters were required due to the specialization supplying one or more (but not all) of them, and/or if the template arguments were used in a form that was modified by the specialization pattern. E.g.

A specialization that is partial because the specialization is supplying at least one, but not all, of the template arguments.

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

A specialization that is partial because the specialization is causing the supplied template argument to be used only partially.

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

In this second example if the template were instantiated using A<char*> then T within the template would actually be of type char, i.e. the template argument as supplied is used only partially due to the application of the specialization pattern.

If that is correct then wouldn't that make the template in the original question a full specialization rather than a partial specialization, and if that is not so then where is my misunderstanding?

Upvotes: 4

Views: 233

Answers (2)

jrok
jrok

Reputation: 55425

It is a partial class template specialization for the case when the same type is passed for both parameters.

Maybe this will be easier to read:

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

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

EDIT:

When in doubt whether a specialization is an explicit (full) specialization or a partial specialization, you can refer to the standard which is pretty clear on this matter:

n3337, 14.7.3./1

An explicit specialization of any of the following:

[...]

can be declared by a declaration introduced by template<>; that is:

explicit-specialization:
template < > declaration

and n3337, 14.5.5/1

A primary class template declaration is one in which the class template name is an identifier. A template declaration in which the class template name is a simple-template-id is a partial specialization of the class template named in the simple-template-id. [...]

Where simple-template-id is defined in the grammar like this:

simple-template-id:

template-name < template-argument-list opt >

template-name

identifier

So, wherever there's template<>, it's a full specialization, anything else is a partial specialization.

You can also think about it this way: Full template specialization specializes for exactly one possible instantiation of the primary template. Anything else is a partial specialization. Example in your question is a partial specialization because while it limits the arguments to be of the same type, it still allows for indifinitely many distinct arguments the template can be instantiated with.

A specialization like this, for example

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

is a full specialization because it kicks in when the type is bool and only bool.

Hope that helps.


And just a note I feel it's worth mentioning. I guess you already know - function templates can't be partialy specialized. While this

template<typename T>
void foo(T);

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

might looks like a partial specialization of foo for pointers on the first glance, it is not - it's an overload.

Upvotes: 11

AnT stands with Russia
AnT stands with Russia

Reputation: 320777

You mention specifying "full or partial types" when performing specialization of a template, which suggests that you are aware of such language feature as partial specialization of class templates.

Partial specialization has rather extensive functionality. It is not limited to simply specifying concrete arguments for some of the template parameters. It also allows defining a dedicated version of template for a certain groups of argument types, based on their cv-qualifications or levels of indirection, as in the following example

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`

And it also covers specializations based on whether some template arguments are identical or different

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

As another, rather curios example, partial specialization of a multi-argument template can be used to fully override the main template

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

Now, returning to your code sample, partial specialization for two identical arguments is exactly what is used in the code you posted.

Upvotes: 5

Related Questions