Trouble specializing a member function in a template class

J

Jeff

/* --------------------------------------------------------------------------
Hello,

I was experimenting with class templates and specializing member
functions and came across a simple problem which I can't figure out.
I have a simple class C with 2 template member objects, and a function
print() that prints the value of these objects. I defined a
specialization of print() for C<string, char> which is called
correctly. Then I wanted to define a specialization of print() that
would be called for C<class T, int>, where T is any type. I couldn't
get this code to compile, let alone run, and tried various ways to
make it work. The full source is below.

Is there a nice solution to this problem? I read somewhere (can't
recall where) that you can't specialize member functions for classes
without specializing the whole class, and yet the C<string,
char>::print() specialization works.

Jeff
---------------------------------------------------------------------------
*/


#include <iostream>
#include <string>
using namespace std;


template<class A, class B>
class C {
public:
C(A a, B b) : a_(a), b_(b) {}

A a_;
B b_;
void print() const;
};


// Template definition of print()
template<class A, class B> void C<A, B>::print() const
{ cout << "Output: " << a_ << ", " << b_ << endl; }


// Full specialization of print() for <string, char> types
template<> void C<string, char>::print() const {
cout << "C<string, char> output: " << a_ << " ... " << b_ << endl;
}


// Trouble here ---------------------------------------------
// the following partial specialization gives the compiler error:
// a.cpp:33: no `void C<A, int>::print() const' member function
declared in class `C<A, int>'
// a.cpp:33: template definition of non-template `void C<A,
int>::print() const'
// (using GCC 3.2)

// if B is type int, call this...
//template<class A, int> //doesn't work
//template<class A, class B> // doesn't work
template<class A> // doesn't work
void
C<A, int>::print() const {
cout << "C<A, int> output: ";
for (int i=0; i<b_; ++i) { cout << a_ << endl; }
cout << endl;
}
// end of Trouble -------------------------------------------


int main() {
// calls template definition, prints "Output: a, 1.23456"
C<char, float> myC('a', 1.23456);
myC.print();
cout << endl;

// calls full specialization successfully, prints "C<string, char>
output: hello there ... b"
C<string, char> C2("hello there", 'z');
C2.print();
cout << endl;

// should call partial specialization, want it to print "C<A, int>
output: boo!boo!boo!boo!boo!"
C<string, int> pc("boo!", 5);
pc.print();
cout << endl;

return 0;
}
 
R

Rob Williscroft

Jeff wrote in
I was experimenting with class templates and specializing member
functions and came across a simple problem which I can't figure out.
I have a simple class C with 2 template member objects, and a function
print() that prints the value of these objects. I defined a
specialization of print() for C<string, char> which is called
correctly. Then I wanted to define a specialization of print() that
would be called for C<class T, int>, where T is any type. I couldn't
get this code to compile, let alone run, and tried various ways to
make it work. The full source is below.

Your problem is that you are trying to create a partial specialization
of a function (non-static member in this case, but that doesn't matter).
For some reason this is not allowed by the language (possibly the
standards committee thought overloading was enough). The workaround
as always is to add another layey of indirection (see below).
Is there a nice solution to this problem? I read somewhere (can't
recall where) that you can't specialize member functions for classes
without specializing the whole class, and yet the C<string,
char>::print() specialization works.


#include <iostream>
#include <typeinfo>

struct example
{
template < typename U, typename V >
void patialy_specialized( U const &u, V const &v );

};

/* helper class
*/
template < typename U, typename V >
struct example_patialy_specialized
{
static void apply( example * that, U const &u, V const &v )
{
std::cerr
<< "default version "
<< typeid( U ).name()
<< " - "
<< typeid( V ).name()
<< "\n"
;
}
};

/* defenition of template method, indirects through the
"helper" above or (importantly) one of its specializations.
*/
template < typename U, typename V >
inline void example::patialy_specialized( U const &u, V const &v)
{
return example_patialy_specialized< U, V >::apply( this, u, v );
}

/* demo specialization of the "helper"
*/
template < typename U >
struct example_patialy_specialized< U, int >
{
static void apply( example * that, U const &arg, int )
{
std::cerr << "U int version " << typeid( U ).name() << "\n";
}
};

int main()
{
example ex;
double d = 1;

ex.patialy_specialized( d, d ); // default
ex.patialy_specialized( d, 1 ); // partial specialization
}

HTH

Rob.
 
J

Jeff

Thanks Rob, got it. I guess I'd need to make the
example_patialy_specialized<U, V> template a friend inside the
example<U, V> template to access any of the private member data. Kind
of unfortunate, it clutters up what seems to be a fairly simple
problem (mind you, I have no need for it yet, just testing)... but
that's templates for you.

Thanks again, a big help.
Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top