Search code examples
c++templatesclass-template

C++ - Template Specialization & Partial Specialization


I have been looking all over the internet and stackoverflow for a concrete answer but I can't seem to find one. I have to create a generic class and then implement specific functions. My specific instructions were: You need to make use of Template Expression Parameters and Template Class Specialization and Partial Specialization.

I have a template class:

template <class T, int x, int y>
class Z {
    T **array[x][y];
    public:
         Z();
         void print();
         //and other methods
};

I need to:

1) Only Z's where x= 2 and y = 2 need to have a public method void J()

2) For char Z's of x = 2 and y= 2 J will do something; for everything else it does something else

3) For only Z's where T is char will the array be initialized to some value. For everything else it's 0

Naturally, this works:

template<class T, int x, int y>
Z<T,x,y>::Z<T,x,y>() { //initialize to 0 } 

But this doesn't:

template<int x, int y>
Z<char,x,y>::Z<char,x,y>() { //initialize to something}

And likewise (assume J exists) this does not work:

template <class T>
void Z<T,2,2>::J() { //something }

My question is:

Is there any simple method for implementing the above items? I need to keep all the other methods in Z. Giving a hint or pointing in the right direction (maybe I missed a question since there are a lot) would be helpful.

Thanks.


Solution

  • It seems you want to define only some functions of some specializations : if print() does not change between the char specialization and the general case, it seems that you don't want to redefine it.

    // What you want to do (illegal in C++)
    template<int,typename T>
    struct Z
    {
        T myValue;
        Z();
        void print() { /* ... */ }
    };
    
    template<int i, typename T>
    Z<i,T>::Z() { /* ... */ }
    
    template<int i>
    Z<i,char>::Z() { /* ... */ }
    

    However, it does not work like this. Partial or full specializations of class have almost nothing in common, except 'prototype' of template parameters:

    // The two following types have only two things related: the template parameter is an int,
    // and the second type is a full specialization of the first. There are no relations between
    // the content of these 2 types.
    template<int> struct A {};
    template<> struct A<42> { void work(); };
    

    You have to declare and define each (partial) specialization:

    // Fixed example
    template<int,typename T>
    struct Z
    {
        T myValue;
        Z();
        void print() { /* ... */ }
    };
    template<int i, typename T>
    Z<i,T>::Z() { /* ... */ }
    
    // Specialization for <all-ints,char>
    template<int i>
    struct Z<i,char>
    {
        char myValue;
        char othervalue;
        Z();
        void print() { /* Same code than for the general case */ }
    };
    
    template<int i>
    Z<i,char>::Z() { /* ... */ }
    

    The only way to escape the code duplication is by using inheritance of traits:

    // Example with the print function
    template<typename T>
    struct print_helper
    {
        void print() { /* ... */ }
    };
    
    // Fixed example
    template<int,typename T>
    struct Z : public print_helper<T>
    {
        T myValue;
        Z();
    };
    template<int i, typename T>
    Z<i,T>::Z() { /* ... */ }
    
    // Specialization for <all-ints,char>
    template<int i>
    struct Z<i,char> : public print_helper<char>
    {
        char myValue;
        char othervalue;
        Z();
    };
    
    template<int i>
    Z<i,char>::Z() { /* ... */ }
    

    You cannot do what you want without duplication for the moment (the feature removing code duplication is static if and has been proposed for the next C++ standard, see n3322 and n3329).