简体   繁体   中英

Specialization of template template parameters

This is a sequel question (on a different topic) to an earlier question . The code below incorporates Dehstil's suggestion to use specialization.

How should a function that has template template parameters be specialized?

The code below (in which the two specialization lines do not compile) make the question concrete.

#include <cassert>

template<typename S> struct PA1 {};
template<typename S> struct PA2 {};
template<typename S> struct PB  {};
template<typename S> struct PC  {};

template<typename S> struct A1 { typedef PA1<S> P; };
template<typename S> struct A2 { typedef PA2<S> P; };
template<typename S> struct B  { typedef PB <S> P; };
template<typename S> struct C  { typedef PC <S> P; };

template<typename S, template<typename> class T> char fn(typename T<S>::P);

template<typename S, template<typename> class T> char fn(typename T<S>::P)
{
    return 'a';
}

template<typename S> char fn<B<S> >(B<S>::P) {   return 'b';  }
template<typename S> char fn<C<S> >(C<S>::P) {   return 'c';  }

int main()
{
    PA1<int> pa1;
    PA2<int> pa2;
    PB<int>  pb;
    PC<int>  pc;
    assert( (fn<int, A1>(pa1)) == 'a' );
    assert( (fn<int, A2>(pa2)) == 'a' );

    assert( (fn<int, B>(pb)) == 'b' );
    assert( (fn<int, C>(pc)) == 'c' );
}

It's important for the four function calls fn<...,...>() to have identical signatures when called since they will themselves reside in a template class that applies to the four classes A1/A2/B/C.

Partial Specialization of function template is NOT allowed by the C++ Standard!

Overload your functions instead of specializing them.

Read the explanation as to Why Not Specialize Function Templates? by Herb Sutter

Then read why to overload than specialize : Template Specialization and Overloading by Herb Sutter


How to call all functions uniformly if you overload

Write a class template call and specialize them as:

template<class S, template<typename> class T>
struct call
{
    static char fn(typename T<S>::P &p)
    {
         return ::fn<S,T>(p);
    }
};

template<class S>
struct call<S,B>
{
    static char fn(typename B<S>::P &p)
    {
         return ::fn<S>(p);
    }
};

template<class S>
struct call<S,C>
{
    static char fn(typename C<S>::P &p)
    {
         return ::fn<S>(p);
    }
};

Then you can use this class template to call all the functions uniformly as:

assert( (call<int, A1>::fn(pa1)) == 'a' );
assert( (call<int, A2>::fn(pa2)) == 'a' );

assert( (call<int, B>::fn(pb)) == 'b' );
assert( (call<int, C>::fn(pc)) == 'c' );

See the online demo : http://www.ideone.com/TISIT

Note also the overloaded function templates in the complete solution at ideone.com (above link)

Functions can be only fully specialized. Use function overloading:

template<typename S> char fn(typename B<S>::P) {   return 'b';  }
template<typename S> char fn(typename C<S>::P) {   return 'c';  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM