Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Template magic needed, partial specialization

Reply
Thread Tools

Template magic needed, partial specialization

 
 
Niklas Norrthon
Guest
Posts: n/a
 
      12-06-2005
I've been banging my head in the wall for some time now over a
little problem having to do with partial specialization of
function templates.

The real problem is more complex than this, but after trimming
out irrelevant stuff, this is what remains. The problem is to
have a function template with different specialization for
signed an unsigned template parameters. Lets assume for now that
I want to test signed arguments for negative values and do
something special with these cases, while unsigned arguments
should not be tested at all.

Consider the following code:

#include <iostream>
#include <limits>

/*
* Helper function called by f<IntType>.
*/
template <typename IntType, bool is_signed> void g(IntType x);

/* Now I want to have two specializations of the above: */
template <typename IntType>
void g<IntType, true>(IntType x) /* Signed types end up here */
{
if (x < 0) { /* ok, x is signed */
/* Special logic here */
}
}

template <typename IntType>
void g<IntType, false>(IntType)
{
/* x is unsigned, so don't have to do anything */
}

/*
* Function called by main. Only template parameter
* is the IntType.
*/
template <typename IntType>
void
f(IntType x)
{
#if 0
/* This would result in compiler warnings if IntType is unsigned: */
if (numeric_limits<IntType>::is_signed && x < 0) {
/* special logic here */
}
#else
/* So let's try this instead */
g<IntType, numeric_limits<IntType>::is_signed>(x);

#endif
/* More logic here */
}

int
main()
{
unsigned char uc = -1;
unsigned short us = -1;
unsigned int ui = -1;
unsigned long ul = -1L;
signed char sc = -1;
signed short ss = -1;
signed int si = -1;
signed long sl = -1L;

f(uc);
f(us);
f(ui);
f(ul);

f(sc);
f(ss);
f(si);
f(sl);

return 0;
}

The compiler complains with the following message:
foo.cc:11: error: function template partial specialization
'g<IntType, true>' is not allowed

I'd appreciate some hints how to get on.

When this is solved I'll have to deal with right shifting:

typedef unsigned short MyInt;
const MyInt my_int_mask = -1;

template <typename UnsignedIntType>
void f(UnsignedIntType x)
{

while (x > 0) {
MyInt y = x /* & my_int_mask */;
/* do something with y */
/* next line does not work if sizeof y >= sizeof x */
x >>= numeric_limits<MyInt>::digits; /* more template magic needed */
}
}

/Niklas Norrthon
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      12-06-2005
* Niklas Norrthon:
>
> I've been banging my head in the wall for some time now over a
> little problem having to do with partial specialization of
> function templates.


You're aware that there's no such?


> The real problem is more complex than this, but after trimming
> out irrelevant stuff, this is what remains. The problem is to
> have a function template with different specialization for
> signed an unsigned template parameters. Lets assume for now that
> I want to test signed arguments for negative values and do
> something special with these cases, while unsigned arguments
> should not be tested at all.


To detect signedness at compile time you can do something like

template< typename T >
struct IsSigned
{
enum{ yes = (T(-1) < 0), no = !yes };
};

int main()
{
std::cout << IsSigned<unsigned>::yes << std::endl;
std::cout << IsSigned<signed>::yes << std::endl;
}


> Consider the following code:
>

[snip]
> template <typename IntType>
> void
> f(IntType x)
> {
> #if 0
> /* This would result in compiler warnings if IntType is unsigned: */
> if (numeric_limits<IntType>::is_signed && x < 0) {
> /* special logic here */
> }
> #else
> /* So let's try this instead */
> g<IntType, numeric_limits<IntType>::is_signed>(x);


You can't use the result of a run-time call at compile time.


[snip]
> I'd appreciate some hints how to get on.


The best is to write code that's signedness-agnostic.

Failing that, you can use the technique shown above.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
 
Niklas Norrthon
Guest
Posts: n/a
 
      12-07-2005
http://www.velocityreviews.com/forums/(E-Mail Removed) (Alf P. Steinbach) writes:

> * Niklas Norrthon:
> >
> > I've been banging my head in the wall for some time now over a
> > little problem having to do with partial specialization of
> > function templates.

>
> You're aware that there's no such?


Now I am, after digging out the standard and looking for it, and
some googling of the archives. I also became aware of that I'm
not the only one missing partial specialization of function
templates, and I see no reason why it couldn't be included in
the language, so I hope it'll find it way in eventually.
>
> To detect signedness at compile time you can do something like
>
> template< typename T >
> struct IsSigned
> {
> enum{ yes = (T(-1) < 0), no = !yes };
> };
>
> int main()
> {
> std::cout << IsSigned<unsigned>::yes << std::endl;
> std::cout << IsSigned<signed>::yes << std::endl;
> }


Which leaves me with exactly the same compiler warning I wanted to
get rid of in the first place.

I admit it's no big deal. The compiler warns me that comparing
an unsigned to less than zero will always result in false. The
problem is that it is in a template, so I will get the warning
for every type I instanciate the template with, and each warning
is three or four lines, since it also tells me where the
template is instanciated and so on, and the code lives in a
header file, so I get it for every file including the header,
which in the end leaves me with pages of useless warnings.

It also gave me the opportunity to dig into some pretty advanced
template hacking, which is something I don't do every day, and
I have learned (I think) when and why I need to say
template<> sometimes, and when I need to specify types with
typename.

> > Consider the following code:
> >

> [snip]
> > template <typename IntType>
> > void
> > f(IntType x)
> > {
> > #if 0
> > /* This would result in compiler warnings if IntType is unsigned: */
> > if (numeric_limits<IntType>::is_signed && x < 0) {
> > /* special logic here */
> > }
> > #else
> > /* So let's try this instead */
> > g<IntType, numeric_limits<IntType>::is_signed>(x);

>
> You can't use the result of a run-time call at compile time.


What are you talking about?
IntType is the template argument from above, known at compile time.
numeric_limits<IntType>::is_signed is a static constant bool
defined in the header <limits> for all built in types, and also
known at compile time. The above would expand to one of:

g<unsigned char, false>(x);
g<signed char, true>(x);
g<char, true>(x);
g<char, false>(x);
g<unsigned short, false>(x);
g<signed short, true>(x);
g<unsigned int, false>(x);
g<signed int, true>(x);
g<unsigned long, false>(x);
g<signed long, true>(x);

Or some other user defined type for which numeric_limits is specialized.

> [snip]
> > I'd appreciate some hints how to get on.

>
> The best is to write code that's signedness-agnostic.
>
> Failing that, you can use the technique shown above.


Failing that, the outcommented code works fine. I just wanted to
get rid of loads of warnings, and learning some advanced
template programming. I did the latter but not the former...

/Niklas Norrthon
 
Reply With Quote
 
Niklas Norrthon
Guest
Posts: n/a
 
      12-07-2005
Niklas Norrthon <(E-Mail Removed)> writes:

> I've been banging my head in the wall for some time now over a
> little problem having to do with partial specialization of
> function templates.


Finally I found a solution to my problem, that I think is
useful enough to share.

/*
* Instead of partial specialization of the function
* templates, first I introduce a dummy template class
* with two possible specializations:
*/

template <bool is_signed>
struct IsSigned { };

/*
* Then I define two versions of the function where the
* actual logic resides. They are overloaded with the
* dummy class above:
*/

/* signed version: */
template <typename IntType>
void g(IntType x, Signed<true> /* dummy arg */)
{
if (x < 0) {
/* special logic here */
}
}

/* Unsigned version */
template <typename IntType>
void g(IntType x, Signed<false> /* dummy arg */)
{
/* do nothing, or do special unsigned logic here */
}

/*
* Finally I have the one parameter version, which
* is called from outside:
*/

/* Common version */
template <typename IntType>
void g(IntType x)
{
/* First special treatment depending on signedness: */
g(x, Signed<numeric_limits<IntType>::is_signed>());

/* Then common logic to both signed and unsigned types */
}

/* Finally my main unchanged from before: */

> int
> main()
> {
> unsigned char uc = -1;
> unsigned short us = -1;
> unsigned int ui = -1;
> unsigned long ul = -1L;
> signed char sc = -1;
> signed short ss = -1;
> signed int si = -1;
> signed long sl = -1L;
>
> f(uc);
> f(us);
> f(ui);
> f(ul);
>
> f(sc);
> f(ss);
> f(si);
> f(sl);
>
> return 0;
> }


/Niklas Norrthon
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      12-07-2005
* Niklas Norrthon:
> * Alf P. Steinbach:
>
> >
> > To detect signedness at compile time you can do something like
> >
> > template< typename T >
> > struct IsSigned
> > {
> > enum{ yes = (T(-1) < 0), no = !yes };
> > };
> >
> > int main()
> > {
> > std::cout << IsSigned<unsigned>::yes << std::endl;
> > std::cout << IsSigned<signed>::yes << std::endl;
> > }

>
> Which leaves me with exactly the same compiler warning I wanted to
> get rid of in the first place.


If that warning is due to your having no partial specialization,
consider the simple trick of putting your function in a class. Classes
can be partially specialized. Another trick is to use function
overloading: you can't partially specialize a function, but you can
overload it, so in this case transform the boolean value to a type, one
for true and one for false, and use a dummy argument of that type.


> > > /* So let's try this instead */
> > > g<IntType, numeric_limits<IntType>::is_signed>(x);

> >
> > You can't use the result of a run-time call at compile time.

>
> What are you talking about?


I'm very sorry, bowing head in shame and applying the nearest wall to my
forehead: it was a parse error, on my part, and furthermore there was no
need for my IsSigned class (except it's usually faster to just code such
a thing than read the docs...).


[snip]
> Failing that, the outcommented code works fine. I just wanted to
> get rid of loads of warnings, and learning some advanced
> template programming. I did the latter but not the former...


Hope the above helps with both, then,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Niklas Norrthon
Guest
Posts: n/a
 
      12-07-2005
(E-Mail Removed) (Alf P. Steinbach) writes:

> If that warning is due to your having no partial specialization,
> consider the simple trick of putting your function in a class. Classes
> can be partially specialized. Another trick is to use function
> overloading: you can't partially specialize a function, but you can
> overload it, so in this case transform the boolean value to a type, one
> for true and one for false, and use a dummy argument of that type.


This is exactly what I ended up with, see my other post. Partial
specializations of function templates would have been a little bit
more elegant IMHO, but overloading with a dummy argument works, so
for the time being that is what I'll do.

Still hope for partial specializations in the future though, and I
see no reason not to include them in the language sooner or later.

> Hope the above helps with both, then,


Thanks for your comments, problem finally solved. (Also the
right_shift part which a mentioned in my original post, which
was trivial in the end).

/Niklas Norrthon
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Template template partial specialization Hizo C++ 17 03-07-2011 08:09 AM
how to do partial specialization template for non member method template vj C++ 1 12-20-2010 11:57 AM
syntax problem for partial template specialization for a template class. toton C++ 1 12-28-2006 04:08 PM
template specialization overriding non-specialization? Joseph Turian C++ 2 04-16-2006 02:46 PM



Advertisments