Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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*&GT; 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?

like image 638
Neutrino Avatar asked Dec 04 '22 10:12

Neutrino


1 Answers

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.

like image 171
jrok Avatar answered Dec 06 '22 23:12

jrok