Templates, specialization

K

Kalle Rutanen

Here is a short code. I can't see why the template specialization does
not work (vsnet2003)? Does the standard allow these kind of
specializations?

template <int i>
class B {};

template <typename T>
class A
{
public:
void f();
};

template <typename T>
void A<T>::f()
{
}

template <int i>
void A<B<i> >::f()
{
}

int main()
{
A<B<2> > a;
a.f();

return 0;
}
 
F

Ferdi Smit

Kalle said:
Here is a short code. I can't see why the template specialization does
not work (vsnet2003)? Does the standard allow these kind of
specializations?

template <int i>
class B {};

template <typename T>
class A
{
public:
void f();
};

template <typename T>
void A<T>::f()
{
}

template <int i>
void A<B<i> >::f()
{
}

int main()
{
A<B<2> > a;
a.f();

return 0;
}

You're basically trying to partially specialize a function now; that
won't work. It does work however if you partially specialize the class,
and then define the member function out of the class. Ie. add the
following few lines:

template <int i>
class A<B<i> > {
public:
void f();
};


--
Regards,

Ferdi Smit
Email: (e-mail address removed)
Room: C0.07 Phone: 4229
INS3 Visualization and 3D Interfaces
CWI Amsterdam, The Netherlands
 
J

John Carson

Kalle Rutanen said:
Here is a short code. I can't see why the template specialization does
not work (vsnet2003)? Does the standard allow these kind of
specializations?

No, it doesn't.
template <int i>
class B {};

template <typename T>
class A
{
public:
void f();
};

So A has a type parameter.
template <typename T>
void A<T>::f()
{
}

template <int i>
void A<B<i> >::f()
{
}

Now, you are trying to give it a non-type parameter. This isn't really
specialization at all. It is a change in the nature of the template from one
having a type parameter to one having a non-type parameter.
int main()
{
A<B<2> > a;
a.f();

return 0;
}

Your example doesn't give much indication what you are trying to achieve.
Making a guess, something resembling what you want might be achieved
with partial specialisation, as follows:

#include <iostream>
using namespace std;

template <int i>
class B {};

template <typename T, int i=0>
class A
{
public:
void f();
};

template <typename T, int i>
void A<T,i>::f()
{
cout << "Member function of general class\n";
}

// We can't partially specialize a function,
// only a class, so we partially specialize the class
// to depend on int only

template <int i>
class A<B<i> >
{
public:
void f();
};

// Now we can define the member function of the partially
// specialized class.
template <int i>
void A<B<i> >::f()
{
cout << "Member function of partially specialized class\n";
}

int main()
{
A<char *> a1;
A<B<2> > a2;
a1.f();
a2.f();

return 0;
}
 
J

John Carson

Ferdi Smit said:
You're basically trying to partially specialize a function now; that
won't work. It does work however if you partially specialize the
class, and then define the member function out of the class. Ie. add
the following few lines:

template <int i>
class A<B<i> > {
public:
void f();
};

Interesting code. I didn't realise it was possible. You appear to have
partially specialized class A to depend only on int when it didn't depend on
int to begin with --- at least not necessarily. Nevertheless, your code
plainly works and I see, upon checking, that Vandevoorde and Josuttis (C++
Templates) give an example (p. 351) where partial specialization involves
the introduction of a new parameter. Good to know. Thank you.
 
J

John Carson

John Carson said:
So A has a type parameter.


Now, you are trying to give it a non-type parameter. This isn't really
specialization at all. It is a change in the nature of the template
from one having a type parameter to one having a non-type parameter.

From Ferdi's post, I have now learned that this type of switch is indeed
possible for classes, though not for functions since it counts as a form of
partial specialization. I stand corrected.
 
K

Kalle Rutanen

Hello, John and Ferdi.

It is indeed possible to specialize the class in the way Ferdi
mentioned. I am surprised too see the given situation really is
forbidden. "C++ in a nutshell", page 195: "You cannot partially
specialize a member of a class template."

But we can still explicitly specialize:

template <>
void A<B<1> >::f()
{
}

Can you think of a reason why this decision was made?

My intention is to convert pixel color formats to each other using
template meta programming (for example ARGB8888 <-> ARGB1555). You can
see the actual code here:

http://kaba.hilvi.org/project/convert/

Look at imageformatconvert.h and imageformatconvert.inl. There (.h) I
had to explicitly specialize the ImageFormatConvert template class three
times (like Ferdi suggested), while the code for them is practically
identical.
 
F

Ferdi Smit

Kalle said:
Hello, John and Ferdi.

It is indeed possible to specialize the class in the way Ferdi
mentioned. I am surprised too see the given situation really is
forbidden. "C++ in a nutshell", page 195: "You cannot partially
specialize a member of a class template."

But we can still explicitly specialize:

template <>
void A<B<1> >::f()
{
}

Can you think of a reason why this decision was made?

You can't partially specialize functions. Instead you have overloading,
which is very powerful. Just remember: functions -> overloading, class
-> specialization. (Explicitly) specializing functions can also cause
some troubles when overloading is used as well. Prefer overloading.
My intention is to convert pixel color formats to each other using
template meta programming (for example ARGB8888 <-> ARGB1555). You can
see the actual code here:

http://kaba.hilvi.org/project/convert/

Look at imageformatconvert.h and imageformatconvert.inl. There (.h) I
had to explicitly specialize the ImageFormatConvert template class three
times (like Ferdi suggested), while the code for them is practically
identical.

You could use overloading with a tag type in your original example.

Ie. something like this (untested, top of my head):

template <int i>
struct B{};

struct default_tag {};
struct special_tag {};

template <typename T>
struct select_conversion {
typedef default_tag tag;
};

template <int i>
struct select_conversion<B<i> > {
typedef special_tag tag;
};


template <typename T>
class A {
public:
void f() {
// do common stuff

// do type specific stuff
f_(typename select_conversion<T>::tag());
}
private:
// select on overloading tag type
void f_(const default_tag& x) {}
void f_(const special_tag& x) {}
};


A<int> ai;
A<B<2> > ab;
ai.f();
ab.f();

Or something similar.

--
Regards,

Ferdi Smit (M.Sc.)
Email: (e-mail address removed)
Room: C0.07 Phone: 4229
INS3 Visualization and 3D Interfaces
CWI Amsterdam, The Netherlands
 

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

Forum statistics

Threads
474,294
Messages
2,571,511
Members
48,202
Latest member
ClaudioVil

Latest Threads

Top