Solved

Partial Template Specialization

Posted on 2003-12-03
35
1,524 Views
Last Modified: 2013-12-14
I just got my Visual Studio 2003 upgrade from amazon.com and I'm trying to figure out how partial template specialization works.

I have managed to get this working:

template<class A, class B>
struct Test {
     A add(A aa, B bb) { return aa+bb; }
}

template<class A>
struct Test<A,int> {
     A add(A aa, int bb) { return aa+bb*bb; }
}

int main()
{
    A<double,double> a;
    cout << a.add(2.5,3.6);
    A<double,int> b;
    cout << b.add(2.5,2);
}

And when passing an integer value to the second param, the integer is squared (and no it wasn't meant to make any sense)

But is it possible to just specialize select methods of a class?

I have a 1000 line class that I would like to specialize for one template argument. Only 3 methods need be changed however so duplicating the whole 1000 lines of the class for that just creates a maintenance nightmare.

So, using the example above, how can I specialize the add method for integers without creating a duplicate of class A. Is it even possible?

If not what's a good workaround? Move all methods that won't be changed to a base class and then create a specialized child class that only contains methods that need to be modified for different template arguments?

-Sandra

0
Comment
Question by:Sandra-24
  • 15
  • 13
  • 3
  • +2
35 Comments
 
LVL 30

Accepted Solution

by:
Axter earned 300 total points
ID: 9873718
You can't partially specialize a member function without partially
specializing the whole class.
0
 
LVL 30

Assisted Solution

by:Axter
Axter earned 300 total points
ID: 9873798
If you have common code that you which to share with all your specilize objects, an easy work around is to have your class derive from a base class that has all the common functions.
You can then use specialization for your derived objects to add specific functionality.

Here's an example:

template<class A, class B>
struct foo_main {
      A add(A aa, B bb) { return aa+bb; }
      A mul(A aa, B bb) { return aa*bb; }
      A minus(A aa, B bb) { return aa-bb; }
      A div(A aa, B bb) { return aa/bb; }
      A a;
      B b;
};

template<class A, class B>
struct foo : public foo_main<A,B>{
};

template<class A>
struct foo<A,int> : public foo_main<A,int> {
      A add(A aa, int bb) { return aa+bb*bb; }
};


int _tmain(int argc, _TCHAR* argv[])
{
      foo<double,double> a;
      cout << a.add(2.5,2) << endl;
      cout << a.mul(2.5,2) << endl;
      cout << a.minus(2.5,2) << endl;
      cout << a.div(2.5,2) << endl << endl;


      foo<double,int> b;
      cout << b.add(2.5,2) << endl;
      cout << b.mul(2.5,2) << endl;
      cout << b.minus(2.5,2) << endl;
      cout << b.div(2.5,2) << endl << endl;

      system("pause");
      return 0;
}

0
 
LVL 48

Expert Comment

by:AlexFM
ID: 9873883
template<class A, class B>
struct Test
{

    A add(A aa, B bb)
    {
        InnerClass<A, B> i;
        return i.add(aa, bb);
    }


    template<class A, class B>
    class InnerClass
    {
    public:
        A add(A aa, B bb) { return aa + bb; }
    };

    template<class A>
    class InnerClass<A, int>
    {
    public:
        A add(A aa, B bb) { return aa + bb*bb; }
    };
};


int _tmain(int argc, _TCHAR* argv[])
{
    Test<double,double> a;
    cout << a.add(2.5,3.6) << endl;

    Test<double,int> b;
    cout << b.add(2.5,2) << endl;

    return 0;
}

This is simplified version since inner class doesn't use container class members. I hope general case may be solved passing of this parameter or some class members from container to internal class.
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 100 total points
ID: 9873919
And this is generic solution which allows to pass this parameter to inner class:

template<class A, class B>
struct Test
{
    A add(A aa, B bb)
    {
        InnerClass<A, B> i;
        return i.add(aa, bb, this);
    }


    template<class A, class B>
    class InnerClass
    {
    public:
        A add(A aa, B bb, Test<A, B>* pContainer) { return aa + bb + pContainer->n; }
    };

    template<class A>
    class InnerClass<A, int>
    {
    public:
        A add(A aa, B bb, Test<A, B>* pContainer) { return aa + bb*bb + pContainer->n; }
    };

    int n;
};

int _tmain(int argc, _TCHAR* argv[])
{
    Test<double,double> a;
    a.n = 1;
    cout << a.add(2.5,3.6) << endl;

    Test<double,int> b;
    b.n = 10;
    cout << b.add(2.5,2) << endl;

    return 0;
}
0
 
LVL 17

Assisted Solution

by:rstaveley
rstaveley earned 100 total points
ID: 9874000
> You can't partially specialize a member function without partially specializing the whole class

Isn't this an example of a partially specialised member function?

--------8<--------
#include <iostream>

template <class A> struct Test {
        template<class B> A add(A a,B b)
        {
                return a+b;
        }
        A add(A a,int b)
        {
                return a+b*b;
        }
};

int main()
{
        Test<double> a;
        std::cout << "short: " << a.add(1.0,static_cast<short>(2)) << '\n';
        std::cout << "double: " << a.add(1.0,2.0) << '\n';
        std::cout << "int: " << a.add(1.0,2) << '\n';
}
--------8<--------

The short and double get a+b and the int gets a+b*b.
0
 
LVL 3

Expert Comment

by:RJSoft
ID: 9874759
I have been programming for years and I still dont know what a template is really about.

I am not even exactly sure what a template is and why you would want to use one. I only have a vauge ideal. I dont understand if you can create a class and inherit what does a template do better than that?

Of course it took me a while to understand virtual too. (me dumb-o)
I hate anything so abstract that I can never get a clear handle on it.

To me a thing has to have a purpose. A reason for using it and a clear cut one at that. An example and an example that makes sense more than doing something else.

To me this is sorta like when you spill something on a rug. It makes a stain. You can clean the rug and mostly remove the stain but it just doesnt come out the way you expect (nice and clean. Clear cut and simplistic). Then you always gotta walk by that rug and see that dang stain. Sure the rug is clean and everything works, but the stain is still there.

If you could explain it's purpose to me, maybe you could get a better understanding also. Sometimes it helps to explain to others.

I am sure that if you had / have any small misconceptions others would be willing to help.

It sure would help me.

Thanks in advance.

RJ
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9875149
RJ, if you are stained with C programming experience, you should have come across #define.

 #define X(p) \
        p *= 2;\
        printf("p is now doubled and it is now %d\n",p);

You can expand a lot in inline clever stuff using cunning #defines. It is faster than writing a function because it is expanded inline and is also more generic. The doubling would work for an int or a double, but the printf wouldn't look good for the double.

C++ improved on inlining with inline functions, and we should all take a slap on the wrist when we use C' #defines. Inline functions are type-safe and, frankly, easier to use.

 inline void X(int& p) {p *= 2;std::printf("p is now doubled and it is now %d\n",p);}
 inline void X(double& p) {p *= 2;std::printf("p is now doubled and it is now %lf\n",p);}

These do however lose out on the generic aspect of C's #define. I need to write another of these if I want to implement it for a short or for a user-defined class.

So we can get clever by using a template.

  template<class T> inline void X(T& p) {p *= 2;std::cout << "p is now doubled and it is now " << p << '\n';}

That example made use of basic_ostream's operator<< specialisations for different primitives. Unlike the printf, which needs the user to pass the formatting, basic_ostream is specialised to deal with different types. If I create a specialised basic_ostream operator<< and a operator* for a user defined class, I can use X with my user-defined class too.

Does this help?
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9875227
> operator*

operator*=

You knew I meant that!
0
 
LVL 3

Expert Comment

by:RJSoft
ID: 9875719
Ok. The #define explanation was clear cut and the fact that you lose the generic aspect from using inline functions because they require specific data type.

check.

And I see what you mean about printf requiring a specific data type for it's format specifier (%).

check.

>> template<class T> inline void X(T& p) {p *= 2;std::cout << "p is now doubled and it is now " << p << '\n';}

>>If I create a specialised basic_ostream operator<< and a operator* for a user defined class, I can use X with my user-defined class too.

check.

So a specialized template is a way to create a "smart macro" that knows how to handle different data types. It has the advantage of an inline because it has type safe protection and it has the advantage of a #define macro because it allows or is smart enough to calculate with different data types.

True?

So basically to use one I would look for code that needed some similar results but might have different data types.

I assume this definition to extend into classes that create objects as well. So does it make sense that if I had a window from class A and a window from class B and both windows displayed some image for example. Would it be to my advantage to write a template that I could then use to display a jpeg in one and a bitmap in the other? Can you then create an object instance with a template? Or is a template only to be at the function level.

I am wondering about the boundries of practicality and the ordinary common usage as the template was perhaps designed for. I can accept limittations as everything is limitted to some degree.

Also, from what I remember the objective of a function to be inline is to speed up processing right? Something about the compilation process where maybe the compiler would or would not produce faster code by expanding it inline. I dont exactly remember how it does this as it was explained many years ago in C class(at school).

I can see how you implemented a template. I am wondering how far it goes.

RJ

0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9877711
Templates are used for situations where you would overload a function for a different data type, but leave the code unchanged.

For example, most functions that deal with integers can also deal with 64bit integers and 16bit short integers. The code will rarely be modified. So you will create three overloads fo that function and just copy and paste the funtion body for each. Trouble is when you want to change it you now have the code in three places. So you go back and make your modifications to all three. (If another programmer is modifying this function he may not know that he has to chaneg all three which is even worse.) That's still doable. But what if you have a function that works on 50 different types. How about 1000? that's possible in large projects. It gets very unmanageable very quickly. So you use templates instead and you shrink it down to one class, one copy of the code and it's easy to maintain.

For classes it is even more usefull. If you have a class (like vector) that stores an extensible array of elements of one type, you would have to create 1000 version of this class to store 1000 different types. IntVector, StringVector, MyCustomDataTypeVector etc. Much better to use templates, then you don't have to remember what you called the integer vector class etc. And if you change something for the class code...

Once you start using templates a lot you will do some things that just couldn't be done without templates. When you start nesting templates etc.

Hope that helps,
-Sandra

0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9878121
Axter, for once my guess at a good workaround is also what the experts recommend. That's new:) Maybe I'm starting to think like a programmer.
Thanks for the help, I'll implement that right away.

rstaveley, I didn't realize you could do that. It won't work in my situation because I really just want certain member functions to behave differently for a sepcial case of A (see below). So using the technique axter specifies is the best way to acheive that. But I'm certain specializing member functions will come in handy frequently.

The best example I can offer is using std containers.

template<class A>
struct Test {
     A foo;
     pop_front();
}

template<class B>
struct Test<std::vector<B> > {
    std::vector<B> foo;
    pop_front();
}

An implementation of pop_front() will be different for

Test<std::vector<int> >
as opposed to
Test<std::deque<int> >

Since for the deque you can use it's pop_front method, but for vector you will need to create one, or leave pop_front() out all together.

(this is not the actual situation I have, just an example)

To achieve this one must resort to the system Axter shows.
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9878144
AlexFm also provides an interesting workaround. I wouldn't have thought of using a specialized inner class. The implementation is a little more confusing and has the overhead of creating instances of the inner class so I don't think it's as good, but it really depends on the situation.

Thanks guys.

-Sandra
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9879358
RJ,

> I am wondering about the boundries of practicality and the ordinary common usage as the template was perhaps designed for.

Generic programming is something that works well in libraries. It is no coincidence that the C++ standard library is dominated by the standard template library. If you dig around in C++ library headers, you find that you often use templates without being aware of it. If you write C++ code you inevitably *use* templates a lot. However, unless you write library code, you tend to *write* templates relatively infrequently.

Consider the good old ostream& operator<< for a user-defined class. Typically this is what you use to display the class contents in a std::cout. In Europe/USA, we'd tend to write friend ostream& operator<<s for our classes thus:

    std::ostream& operator<<(std::ostream& os,const MyClass& myclass)
    {
          // ...
          return os;
    }

This is a specialisation for narrow characters, making use of a typedef of std::basic_ostream<char> as std::ostream. It is equivalent to:

    std::basic_ostream<char>& operator<<(std::basic_ostream<char>& os,const MyClass& myclass)
    {
          // ...
          return os;
    }

This inevitably *uses* templates because basic_ostream<char> is a template, but it isn't *writing* a template function. If we wanted to write a template, we might put it into a header file thus:

    template <class charT> std::basic_ostream<charT>& operator<< (basic_ostream<charT>& os,const MyClass& myclass)
    {
          // ...
          return os;
    }

We could get more sophisticated and add traits to this, but essentially all that this templatised function gives us is the capability of using the same generic code to display our class in output streams which have either wide or narrow characters. In other word this functions is only actually applicable to two different object types: char and wchar_t.

Do we need the template if we are only using wide characters in a project? No, we'd probably use the alternative wostream specialisation (instead of our ostream):

    std::wostream& operator<<(std::wostream& os,const MyClass& myclass)
    {
          // ...
          return os;
    }

...which itself is equivalent to...

    std::basic_ostream<wchar_t>& operator<<(std::basic_ostream<wchar_t>& os,const MyClass& myclass)
    {
          // ...
          return os;
    }

So, unless you are writing code to put in a toolbox, you are more likely to write specialised code than generic code, because it is easier. If you are writing code for your toolbox, you are more likely to consider writing generic code, because it is more reusable.

> Also, from what I remember the objective of a function to be inline is to speed up processing right?

Correct. When you call any function in C++, there is some overhead associaed with the function call itself. Inline code doesn't have this overhead.

I misled you, if I gave you the impression that template functions are always expanded inline. They may be expanded as ordinary functions too. Template classes (like AlexFM's Test class) are often written with inline functions, but you can allow them to be instantiated as ordinary functions.

Consider the rather arteficial Test class example again (I say arteficial, because there is no real reason to put these functions in a class), but this time with non-inlined functions:
--------8<--------
#include <iostream>

template<class A> struct Test {
        template<class B> A add(A a,B b);
        A add(A a,int b);
};

template<class A> /* inline */ A Test<A>::add(A a,int b)
{
        return a+b*b;
}

template<class A> template<class B> /* inline */ A Test<A>::add(A a,B b)
{
        return a+b;
}

int main()
{
        Test<double> a;
        std::cout << "short: " << a.add(1.0,static_cast<short>(2)) << '\n';
        std::cout << "double: " << a.add(1.0,2.0) << '\n';
        std::cout << "int: " << a.add(1.0,2) << '\n';
}
--------8<--------

By avoiding the inline keyword, these ought to be instantiated as ordinary functions, when the template is expanded for the different types. The disadvantage of this approach is that non-inline functions have more run time overhead than inline functions, and it is therefore slower. The advantage of this approach is that you get less "code bloat", and you should end up with a smaller executable size.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9879376
Sandra, you may be intereted in following illustration of a partial specialisation of the display() function for vectors:
--------8<--------
#include <iostream>
#include <deque>
#include <vector>
#include <string>

// Template designed for container classes
template<class T> struct X : public T {
        void dump();
        void display();
};

// Show the contents of the container
template<class T> void X<T>::dump()
{
        typedef typename T::const_iterator c_itr;
        for (c_itr itr = begin();itr != end();++itr)
                std::cout << *itr << '\n';
}

// General purpose display used for any container
template<class T> void X<T>::display()
{
        std::cout << "This container has:\n";
        dump();
}

// Specialised for X<std::vector<std::string> >
void X<std::vector<std::string> >::display()
{
        std::cout << "This vector has:\n";
        dump();
}

int main()
{

// The deque uses the generic display() function

        X<std::deque<std::string> > d;
        d.push_back("Deque middle");
        d.push_back("Deque back");
        d.push_front("Deque front");
        d.display();

// We have a specialised display() function for std::vector<std::string>

        X<std::vector<std::string> > v;
        v.push_back("Vector front");
        v.push_back("Vector back");
        v.display();
}
--------8<--------

Does this prevent the need for a work-around, or did I misunderstand?
0
 
LVL 30

Expert Comment

by:Axter
ID: 9880063
rstaveley,
>>Isn't this an example of a partially specialised member function?
>>template <class A> struct Test {
 >>      template<class B> A add(A a,B b)
 >>       {
 >>               return a+b;
 >>       }
 >>       A add(A a,int b)
 >>       {
 >>               return a+b*b;
 >>       }
 >>};

No.
That's an example of a overloaded function.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9880883
> That's an example of a overloaded function

Thanks for putting me straight, Axter. If it had been a specialisation it would have been closer to a full specialisation, but without the template<> prefix it is indeed an overloaded function. Coded inline it has the same effect as a specialisation, because it is only expanded and and when required, but if it was not written inline, I guess the code would be instantiated as an ordinarary class function regardless of whether it was actually required or not.

I've looked a bit deeper into this and it looks like you are right that "You can't partially specialize a member function without partially
specializing the whole class", however it looks like you can partially specialise a member function - e.g. the double pointer handling in the following surely qualifies as partial specialisation, doesn't it?
--------8<--------
#include <iostream>

template <class A> struct Test {

        // Here is the general version
        template<class B> A add(A a,B b)
        {
                return a+b;
        }

        // Is this a partial specialisation?
        template<class B> A add(A a,B *b)
        {
                return a+*b+123;
        }

        // Would this be a specialisation?
        // Too bad it doesn't compile!
//      template<> A add(A a,int b)
//      {
//              return a+b+456;
//      }

        // Axter pointed out that this one is an overload
        // and he's right of course!
        A add(A a,int b)
        {
              return a+b+789;
        }
};

int main()
{
        Test<double> a;
        std::cout << "double: " << a.add(1.0,2.0) << '\n';
        std::cout << "double pointer: " << a.add(1.0,new double(2.0)) << '\n';
        std::cout << "int: " << a.add(1.0,2) << '\n';
}
--------8<--------
0
 
LVL 30

Expert Comment

by:Axter
ID: 9881486
>>however it looks like you can partially specialise a member function - e.g. the double pointer handling in the following surely qualifies as partial specialisation, doesn't it?

I'm sorry, but that's also an overloaded function.
Section 14.5.4 Of the C++ standard talks about partial specialization.  The titile of this section is called "Class template partial specializations"
The C++ standard makes no mention of any function template partial specialization.

Section 14.5.4.3 does talk about "Members of class template specializations", and here what it states:
---------------------------------------------------------------------------------------------------------------------------------
If a member template of a class template is partially specialized, the member template partial specializations
are member templates of the enclosing class template; if the enclosing class template is instantiated
(14.7.1, 14.7.2), a declaration for every member template partial specialization is also instantiated as part of
creating the members of the class template specialization. If the primary member template is explicitly specialized
for a given (implicit) specialization of the enclosing class template, the partial specializations of the
member template are ignored for this specialization of the enclosing class template. If a partial specialization
of the member template is explicitly specialized for a given (implicit) specialization of the enclosing
class template, the primary member template and its other partial specializations are still considered for this
specialization of the enclosing class template.
---------------------------------------------------------------------------------------------------------------------------------

Section 14.5.5.1 talks about "Function template overloading"
Here's what it states:
---------------------------------------------------------------------------------------------------------------------------------
It is possible to overload function templates so that two different function template specializations have the
same type. [Example:
// file1.c
template<class T> void f(T*);

// file2.c
template<class T> void f(T);
---------------------------------------------------------------------------------------------------------------------------------

Because you can overload a function, there really is no need for a member function specialization.
As your examples have already pointed out, all you have to do is overload the function to get a specific result for a paticular type.
This is pretty much the same thing that is done with a non-template class member function.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 17

Expert Comment

by:rstaveley
ID: 9881704
> The C++ standard makes no mention of any function template partial specialization

You've thrown me Axter. I was under the impression that the following templates were function template specialisations. Are you saying that only classes can be said to be "specialised" and when I say "specialisation" in the context of functions, I should really be saying "overload"?

--------8<--------
#include <iostream>
#include <sstream>

// General template function
template<class A> std::string doublestr(A a)
{
        std::ostringstream ostr;
        ostr << "(using the general template function) " << a*2;
        return ostr.str();
}

// What rstaveley calls a "Partial specialisation for pointers" (is he wrong??)
template<class A> std::string doublestr(A *a)
{
        std::ostringstream ostr;
        ostr << "(using partially specialised template function which handles pointers to any type) " << *a*2;
        return ostr.str();
}

// What rstaveley calls "Specialisation for int" (is he wrong??)
template<> std::string doublestr(int a)
{
        std::ostringstream ostr;
        ostr << "(using specialised template fuction for an int) " << a*2;
        return ostr.str();
}

int main()
{
        std::cout << "1 plus 1 (double) is " << doublestr(1.0) << '\n';
        std::cout << "1 plus 1 (short pointer) is " << doublestr(new short(1)) << '\n';
        std::cout << "1 plus 1 (int) is " << doublestr(1) << '\n';
}
--------8<--------
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9881892
I notice that the GCC headers describe ostream& operator<< specialisations as "specializations", which means that they certainly use the expression specialisation in the context of template functions.

If you accept that the previous code snippet's function partial specialisation was indeed a "partial specialisation", how can you say that the following struct X's handling of the pointer is done using anything other than a partial specialisation?

--------8<--------
#include <iostream>
#include <sstream>

struct X {

// General template function
template<class A> std::string doublestr(A a)
{
        std::ostringstream ostr;
        ostr << "(using general template function) " << a*2;
        return ostr.str();
}

// Partial specialisation for pointers
template<class A> std::string doublestr(A *a)
{
        std::ostringstream ostr;
        ostr << "(using partially specialised template function) " << *a*2;
        return ostr.str();
}

#if 0 /* Not allowed in the class */
// Specialisation for int
template<> std::string doublestr(int a)
{
        std::ostringstream ostr;
        ostr << "(using specialised template fuction) " << a*2;
        return ostr.str();
}
#endif

}; // End of struct X

int main()
{
        X x;
        std::cout << "1 plus 1 (double) is " << x.doublestr(1.0) << '\n';
        std::cout << "1 plus 1 (short pointer) is " << x.doublestr(new short(1)) << '\n';
        std::cout << "1 plus 1 (int) is " << x.doublestr(1) << '\n';
}
--------8<--------

Leading on from that, how about the template class's handling of the pointer, in the following snippet?
--------8<--------
#include <iostream>
#include <sstream>

template<class B> struct X {

// The multiplier
const B b;

// Constructor
X(B b) : b(b) {}

// General template function
template<class A> std::string mulstr(A a)
{
        std::ostringstream ostr;
        ostr << "(using general template function) " << a*b;
        return ostr.str();
}

// Partial specialisation for pointers
template<class A> std::string mulstr(A *a)
{
        std::ostringstream ostr;
        ostr << "(using partially specialised template function) " << *a*b;
        return ostr.str();
}

#if 0 /* Not allowed in the class */
// Specialisation for int
template<> std::string mulstr(int a)
{
        std::ostringstream ostr;
        ostr << "(using specialised template fuction) " << a*b;
        return ostr.str();
}
#endif

}; // End of template struct X

int main()
{
        X<double> x(3.0);
        std::cout << "1 plus 1 (double) is " << x.mulstr(1.0) << '\n';
        std::cout << "1 plus 1 (short pointer) is " << x.mulstr(new short(1)) << '\n';
        std::cout << "1 plus 1 (int) is " << x.mulstr(1) << '\n';
}
--------8<--------

I'll concede about the non-partial specialisation, which doesn't compile (hence the #if 0) :-)
0
 
LVL 30

Expert Comment

by:Axter
ID: 9886806
>>Are you saying that only classes can be said to be "specialised" and when I say "specialisation" in the context of functions, I should really be saying "overload"?
No.
I'm saying only classes can be *partial* specialized.


>>I notice that the GCC headers describe ostream& operator<< specialisations as "specializations", which means that they certainly use the expression specialisation in the context of template functions.

I've have not looked at the GCC header, but they may be correct in that it is a specialized template function.  But that's not the same as PARTIAL specialization.

>>I was under the impression that the following templates were function template specialisations.

I think you're mixing specialization and partial specialization.

// What rstaveley calls a "Partial specialisation for pointers" (is he wrong??)
>>template<class A> std::string doublestr(A *a)

This is not partial specialization.  I'm not sure if you can even call this specialization.  It's more of an overloaded function.
0
 
LVL 30

Expert Comment

by:Axter
ID: 9886875
FYI:
>>template<class A> std::string doublestr(A *a)

That is considered specialization, but not partial specialization.



>>template<> std::string mulstr(int a)

This looks more like the syntax for explicit specialization.

Example:
template<class T, class T2>
class X
{
public:
      void SomeFunction1()
      {
            cout << "some types" << endl;
      }
};

// explicit specialization
template<> void X<char*,int>::SomeFunction1()
{
      cout << "types char* and int" << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
      X <char*, int>x1;
      x1.SomeFunction1();

      X <long, char>x2;
      x2.SomeFunction1();

      system("pause");
      return 0;
}

0
 
LVL 30

Expert Comment

by:Axter
ID: 9887058
Using the original questioner's code, you can do this with explicit specialization:

template<class A, class B>
struct Test {
      A add(A aa, B bb);
};


template<class A, class B> A Test<A,B>::add(A aa, B bb)
{
      return aa+bb;
}

// explicit specialization
template<> double Test<double,int>::add(double aa, int bb)
{
      return aa+bb*bb;
}

int _tmain(int argc, _TCHAR* argv[])
{
      Test<double,double> a;
      cout << a.add(2.5,3.6) << endl;
      Test<double,int> b;
      cout << b.add(2.5,2) << endl;

      system("pause");
      return 0;
}

But this is not partial specialization, because all template types must be explicitly defined.
If partial specialization was possible for member functions, then you should be able to do the following:

// partial specialization that does not compile
template<class A> A Test<A,int>::add(A aa, int bb)
{
      return aa+bb*bb;
}

But this does not compile, because you can not do partial specialization with member functions.  Only class/struct
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9887486
>That is considered specialization, but not partial specialization

Thanks for being patient with me, Axter. I've understood where my misunderstanding was. I hadn't appreciated that partial specialisation required losing one or more but not all classes from the classes in the <> list.

i.e.

   template<class A,class B>....     // If this is the primary template
   template<class A>....                // .... this is a partial specialisation
   template<>....                          // .... and this is an explicit specialisation

I don't believe that I'm alone in this misunderstanding. I've certainly seen other code that refers to slightly more specific template matches as being "partial specialisations" (code along the lines of 'What rstaveley calls a "Partial specialisation for pointers"' - in my earlier posting), but it wouldn't surprise me if this is a misconception that I've unwittingly been propagating.

However... at the risk of flogging a dead horse... wouldn't you say that the following is a partial specialisation or would you argue that it is an overload, because it requires the prototype in the class definition?
--------8<--------
#include <iostream>
#include <sstream>

template<class C> struct X {
        const C c;
        X(C c) : c(c) {}        // Constructor
        template<class A,class B> std::string addstr(A,B); // Primary template
        template<class A> std::string addstr(A,int); // Partial specialisation of the line above
//      template<> std::string addstr(int,int); // Explicit specialisation doesn't compile
        std::string addstr(int,int); // Overloaded function - not really a specialisation technically
};

// Primary template function
template<class C> template<class A,class B> std::string X<C>::addstr(A a,B b)
{
        std::ostringstream ostr;
        ostr << "(using primary template function) " << a+b+c;
        return ostr.str();
}

// Partial specialisation - specialisation for int b but general for A a
template<class C> template<class A> std::string X<C>::addstr(A a,int b)
{
        std::ostringstream ostr;
        ostr << "(using partially specialised template function) " << a+b+c;
        return ostr.str();
}

//// Explicit specialisation for int a int b can't be compiled
//template<class C> template<> std::string X<C>::addstr(int a,int b)
//{
//      std::ostringstream ostr;
//      ostr << "(using explicit specialised template fuction) " << a+b+c;
//      return ostr.str();
//}

// Overload - I agree this isn't a specialisation :-)
template<class C> std::string X<C>::addstr(int a,int b)
{
        std::ostringstream ostr;
        ostr << "(using overloaded fuction) " << a+b+c;
        return ostr.str();
}

int main()
{
        X<int> x(100);
        std::cout << "1 plus 1 <double,double> plus 100 <int> is " << x.addstr(1.0,1.0) << '\n';
        std::cout << "1 plus 1 <double,int> plus 100 <int> is " << x.addstr(1.0,1) << '\n';
        std::cout << "1 plus 1 <int,int> plus 100 <int> is " << x.addstr(1,1) << '\n';
}
--------8<--------
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9887802
>> FYI:
>>>template<class A> std::string doublestr(A *a)
>
> That is considered specialization, but not partial specialization.

I should have stuck to my guns, Axter. I've just dusted off my copy of Stroustrup's "The C++ Programming Language", and in his section on partial specialisation, this is indeed described as partial specialisation! If this is a misunderstanding, I'm in good company :-)

Better get on with weekending.... Christmas presents to buy.
0
 
LVL 30

Expert Comment

by:Axter
ID: 9887848
>>Better get on with weekending.... Christmas presents to buy.

I have it already. (Special Edition).

What section are you referrring to?
0
 
LVL 30

Expert Comment

by:Axter
ID: 9887899
Maybe I'm over looking something, but in my copy of Stroustrup's book, he has very little to say about partial specialization.
The index refers to one page (page 342).
That page refers to it in two paragraphs without stating what a partial specialization is.  He really doesn’t go into any kind of detail.

The C++ standard does have a specific description for partial specialization.
And the C++ Standard is the higher authority.  In other words, the C++ standard would over rule even what the father of the language has to say about it.

Considering Stroutrup’s book lacks a good definition, I would not put very much weight into trying to interpret what he believes is partial specialization.

Get a copy of the C++ standard, and look up section 14.5.4.

You could also trying looking for the free draft version of the standard on the web.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9889145
>>Better get on with weekending.... Christmas presents to buy.
> I have it already. (Special Edition).

Sorry, I wasn't inferring that you should get it for Xmas. That must have seemed very rude. That was a bit of trivia to explain that I wouldn't be on-line today, and that I might be a bit unresponsive. I need to get presents for the kids :-)

You are right that Stroustrup doesn't define specialisation and the standard is... well the standard. However, if you look in the index for the Special Edition for partial specialisation, you'll find that he is labouring under the same misunderstanding as me.

You are right; I really must get a copy of the standard. Have a good weekend.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9891696
More apologies to Axter. Please have these points for your enduring patience: http:/Q_20818690.html

I'll conclude here, because this is relevant to the thread, and there's always the "Unsubscribe" button, isn't there? :-)

I've just read through Stroustrup's text more carefully. I hadn't spotted the second set of angle brackets in his fuction specialisations. What I was doing wasn't specialisation. It was function overloading, as Axter so patiently pointed out.

I can now see that it isn't possible to do function partial specialisation. GCC's error message is " partial specialization `doublestr<A*>' of function template" in the attempted partial specialsation below, which really couldn't be clearer. Since you also can't do an explicit function specialisation, that makes Axter100% right in his accepted answer.

--------8<--------
#include <iostream>
#include <sstream>

// General template function
template<class A> std::string doublestr(A a)
{
        std::ostringstream ostr;
        ostr << "(using general template function) " << a*2;
        return ostr.str();
}

#if 0
// Partial specialisation for pointers (doesn't compile)
// You can only do partial specialisation of classes, I now realise
template<class A> std::string doublestr<A*>(A* a)
{
        std::ostringstream ostr;
        ostr << "(using partially specialised template function) " << *a*2;
        return ostr.str();
}
#endif

// Specialisation for short*
template <> std::string doublestr<short*>(short *a)
{
        std::ostringstream ostr;
        ostr << "(using specialised short* template function) " << *a*2;
        return ostr.str();
}
int main()
{
        std::cout << "1 plus 1 (double) is " << doublestr(1.0) << '\n';
        std::cout << "1 plus 1 (short pointer) is " << doublestr(new short(1)) << '\n';
}
--------8<--------

GCC 3.2's header for <ostream> has a misleading comment in this respect:
--------8<--------
  // Partial specializationss
  template<class _Traits>
    basic_ostream<char, _Traits>&
    operator<<(basic_ostream<char, _Traits>& __out, const char* __s);
--------8<--------
I may not have been in the company of Stroustrup in calling overloaded functions partial specialisations, but at least I can take comfort that somebody else has made the same mistake too.

It is beyond the scope of this thread, but it is interesting to consider what the *practical* difference is between function specialisations and overloads. None presumably, if they are both inline?
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9891788
> *practical* difference

I can see that it is only possible to instantiate a class, which isn't listed in the function parameters, if you use a specialisation, but otherwise I can't see any practical difference, between a function overload and a function specialisation.
--------8<--------
#include <iostream>

struct U {U(){std::cout << "You've made a U, ";}};
struct W {W(){std::cout << "You've made a W, ";}};
struct X {X(){std::cout << "You've made an X, ";}};
struct Y {Y(){std::cout << "You've made a Y, ";}};
struct Z {Z(){std::cout << "You've made a Z, ";}};

template<class T> void foo() {T t;std::cout << "using the primary template function\n";}
template<> void foo<X>() {X t;std::cout << "using a specialisation for X\n";}
template<> void foo<Z>() {Z t;std::cout << "using a specialisation for Z\n";}
template<class T> void foo(T) {T t;std::cout << "using an overload\n";}

int main()
{
        foo(U()); // <- The overload
        foo<W>();
        foo<X>();
        foo<Y>();
        foo<Z>();
}
--------8<--------
0
 
LVL 30

Expert Comment

by:Axter
ID: 9891793
>>More apologies to Axter. Please have these points for your enduring patience

No apologies needed.  
Often in debates like this, I gain new insights into the language as I look through documentation to verify my position.

That’s one of the reasons I enjoy participating in EE.  Because whether I’m debating or trying to determine the correct answer for a questioner, the process usually improves my skills one way or another.
0
 
LVL 30

Expert Comment

by:Axter
ID: 9891822
>>I can't see any practical difference, between a function overload and a function specialisation.

There is a difference in functionallity and in syntax.

Look at functionallity.

If member function partial specialization were allowed, function "Add" would only allow the second parameter to be of type 'B'
template <class A, class B> struct Test {
      A add(A a,B b)
      {//This would only allow the second parameter to be of type B
            return a+b;
      }
      A add(A a,int b)
      {
            return a+b*b;
      }
};

Here in the overloaded method, the second parameter can be any type.

template <class A, class B> struct Test {
      template<class X> A add(A a,X b)
      {//The second parameter 'X' can be of any type
            return a+b;
      }
      A add(A a,int b)
      {
            return a+b*b;
      }
};


There are ways to fix this problem, but you would have to add a little more code, and/or you would be placing partial limitations on your B type.
Example:
template <class A, class B> struct Test {
      template<class X> A add(A a,X b)
      {
            if (0)
            {
                  B b2 = b;  //Type B would need to have a copy constructor or = operator
            }
            return a;
      }
      A add(A a,int b)
      {
            return a;
      }
};


continue......
0
 
LVL 30

Expert Comment

by:Axter
ID: 9892104
The syntax difference is not very apparent when declared within the class, but when the function implementation is out side of the class, you can see the real differences between function overloading and what would be member function partial specialization if it were allowed.

Here's the function overloaded method with implementation out side of the class declaration:
template <class A, class B> struct Test {
      template<class X> A add(A a,X b);
      A add(A a,int b);
};

template<class A, class B>
template<class X>
A Test<A,B>::add(A a, X b)
{
      return a+b;
}

template<class A, class B> A Test<A,B>::add(A a, int b)
{
      return a+b*b;
}

In the above example, you can see that the overloaded function takes BOTH template arguments as the default function.
There's nothing partial within the template declaration.
This is what makes it an overloaded function instead of a partial specialization.


Using this method, you can get most of the functionallity needed, but it's not an exact duplicate of what you get with partial specialization.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9892965
>> >>I can't see any practical difference, between a function overload and a function specialisation.
>>
>> There is a difference in functionallity and in syntax.

Your examples were with class template specialisation.

My comment about not seeing practical differences was confined to function template specialisation, which I now understand can only be explicit.

If you have the class type in the function parameter list, why bother doing an explicit specialisation, if an overload achieves the same result?

  template <class T> void foo(T); // The primary function template
  template <> void foo<MyClass>(MyClass); // This is an explicit specialisation
  void foo(MyClass); // This is an overload

If the class type isn't in the function the function parameter list, I can see that specialisation allows you to specialise for a specific class type, as illustrated in by "template<> void foo<X>()" in my earlier example, but that is a pretty obscure example, which a different function name would service just as well... would it not?
0
 
LVL 30

Expert Comment

by:Axter
ID: 9893802
>>If you have the class type in the function parameter list, why bother doing an explicit specialisation, if an overload achieves the same result?

That's a good question.  I had to really think about that.

There's only a small difference between the functionallity you would get from a explicit specialization and what you would get from function overloading.

With explicit specialization, you're saying use this specialized function when the class template parameter type matches a certain type.
With function overloading, you're saying use this overloaded function when the *argument* matches a certain type.

Example:
template<class T>
class foo1
{
public:
      void SomeFunc(T t){cout << "T t" << endl;}
      void SomeFunc(int t){cout << "int t" << endl;}
};

template<class T>
class foo2
{
public:
      void SomeFunc(T t){cout << "T t" << endl;}
};
template <> void foo2<int>::SomeFunc(int){cout << "int t" << endl;}

int TestFunc()
{
      foo1<char*> f1;
      foo2<char*> f2;
      f1.SomeFunc(99);//This will not give you a compile error
      f2.SomeFunc(99);//This does give you a compile error

As you can see with the above example, the overloaded function can be access by any foo1<???> type.
However, the explicit specialization function only allows access by a type that matches the class type.  So it only can be accessed by a foo2<int> class.

With out having the safe gard that you get from explicit specialization, you can mistakenly pass the wrong function argument in your code, and the compiler will not give you an error.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9895760
Because you can't do a template function specialisation on member functions in template class, class it is probably better to run examples either on member template functions in a non-template class or in some template-functions. This is easier for me to understand, anyway :-)

1: Template functions. Nothing to do with a class. These may be explicitly specialised, but cannot be partially specialised
--------8<--------
/* Here you have a template function, for which there are specialisations */

#include <iostream>
using std::cout;
using std::endl;

/* No class here. This is simply a template function with two explicit specialisations */
template<class X> void SomeFunc(int){cout << "general" << endl;}
template<> void SomeFunc<int>(int){cout << "specialised for int" << endl;}
template<> void SomeFunc<char*>(int){cout << "specialised for char*" << endl;}

int main()
{
     SomeFunc<long>(99);
     SomeFunc<char*>(99);
     SomeFunc<int>(99);
}
--------8<--------

2: A non-template class with a template function, which is specialised. This is OK.
--------8<--------
/* Here you have a template function in a class, for which there are specialisations */

#include <iostream>
using std::cout;
using std::endl;

class foo3 /* Not a template class */
{
public:
     template<class X> void SomeFunc(int); // A template member function
};

/* This is a class member template function with two explicit specialisations. Remeber that it *isn't* a template class, and we can therefore specialise. */
template <class X> void foo3::SomeFunc(int){cout << "general" << endl;}
template <> void foo3::SomeFunc<int>(int){cout << "specialised for int" << endl;}
template <> void foo3::SomeFunc<char*>(int){cout << "specialised for char*" << endl;}

int main()
{
     foo3 f;
     f.SomeFunc<long>(99);
     f.SomeFunc<char*>(99);
     f.SomeFunc<int>(99);
}
--------8<--------

3: A template class with a template function, which cannot be specialised. I've commented out the function specialisations, because they are forbidden.
--------8<--------
/* Here you have a template function in a template class.
    There cannot be specialisations of that template function! */

#include <iostream>
using std::cout;
using std::endl;

template<class T> class foo4 /* This is a template class */
{
public:
     template<class X> void SomeFunc(int); // A member member function
};

/* Here is the template class's template member function. We cannot specialise this */
template<class T> template<class X> void foo4<T>::SomeFunc(int){cout << "general" << endl;}

/* Cannot specialise a template class's template member function!! */
//template<class T> template<> void foo4<T>::SomeFunc<int>(int){cout << "specialised for int" << endl;}
//template<class T> template<> void foo4<T>::SomeFunc<char*>(int){cout << "specialised for char*" << endl;}

int main()
{
     foo4<doube> f;
     f.SomeFunc<long>(99);
     f.SomeFunc<char*>(99);
     f.SomeFunc<int>(99);
}
--------8<--------

> With out having the safe gard that you get from explicit specialization, you can mistakenly pass the wrong function argument in your code, and the compiler will not give you an error.

I haven't overloaded the SomeFunc template function in the example above, because I was making the template parameter distinct from the function parameter. However, had the template function been written, using the template parameter class type as the function parameter, you wouldn't see any more type-safety than you do in the equivalent function overload.

i.e. Compare the specialisation with the overload

     template<class X> void SomeFunc(X);
     template<> void SomeFunc<const std::string&>(const std::string&); // Here's the specialisation
     void SomeFunc(const std::string&); // Here's an overload
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now