Connecting Tech Pros Worldwide Help | Site Map

Template specialization problems

Yang Zhang
Guest
 
Posts: n/a
#1: Apr 1 '06
I have a small program like this:

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

// set bits in an address
template <typename T>
inline T*
set_addr(const T* addr, unsigned long n) {
return (T*)( (unsigned long)addr | n) ;
}

// helper class that clears the last two bits of an address
template <typename T, int S>
struct clear_addr_helper {} ;

// 32 bit pointer specialization
template <typename T>
struct clear_addr_helper<T,4> {
static inline T*
clear(const T* addr) {
return (T*)( (unsigned long)addr & 0xfffffffc) ;
}
} ;

// 64 bit pointer specialization
template <typename T>
struct clear_addr_helper<T,8> {
static inline T*
clear(const T* addr) {
return (T*)( (unsigned long)addr & 0xfffffffffffffffc) ;
}
// a function that won't compile
static inline void
error() { ss }
} ;

template <typename T>
inline T*
clear_addr(const T* addr) {
return clear_addr_helper<T,sizeof(T*)>::clear(addr) ;
}

int
main() {
short* p = new short(1) ;

cout << "sizeof(short*): " << sizeof(short*) << endl ;
cout << "p = " << p << endl ;
cout << "set_addr(p,0x1): " << set_addr(p,0x1) << endl ;
cout << "clear_addr(set_addr(p,0x2)): "
<< clear_addr(set_addr(p,0x2)) << endl ;
}
////////////////////////////////////////////////

g++ (version 4.0.1) won't compile this program on a 32 bit machine. It
complained the 64 bit specialization: the "0xfffffffffffffffc" in the
"clear" method is too large, and the "error" method is in error. But
since on a 32 bit machine, only the 32 bit pointer template
specialization is needed. It seems that g++ has looked both of them.
Other compilers such as the Intel/Sun Workshop/SGI C++ compilers all
compiled the above code without problem. I think they all didn't look at
the 64 bit pointer template specialization.

Is this behavior implementation dependent? Is there a way (a
command-line option) to make g++ behave like others?? Or I cannot assume
a lazy instantiation for the compiler?

Thanks in advance,
--Yang
Bo Persson
Guest
 
Posts: n/a
#2: Apr 1 '06

re: Template specialization problems



"Yang Zhang" <spam@no.spam.com> skrev i meddelandet
news:W4mXf.3200$L6.2726@bignews5.bellsouth.net...[color=blue]
>I have a small program like this:
>
> ////////////////////////////////////////////////
> #include <iostream>
> using namespace std ;
>
> // set bits in an address
> template <typename T>
> inline T*
> set_addr(const T* addr, unsigned long n) {
> return (T*)( (unsigned long)addr | n) ;
> }
>
> // helper class that clears the last two bits of an address
> template <typename T, int S>
> struct clear_addr_helper {} ;
>
> // 32 bit pointer specialization
> template <typename T>
> struct clear_addr_helper<T,4> {
> static inline T*
> clear(const T* addr) {
> return (T*)( (unsigned long)addr & 0xfffffffc) ;
> }
> } ;
>
> // 64 bit pointer specialization
> template <typename T>
> struct clear_addr_helper<T,8> {
> static inline T*
> clear(const T* addr) {
> return (T*)( (unsigned long)addr & 0xfffffffffffffffc) ;
> }
> // a function that won't compile
> static inline void
> error() { ss }
> } ;
>
> template <typename T>
> inline T*
> clear_addr(const T* addr) {
> return clear_addr_helper<T,sizeof(T*)>::clear(addr) ;
> }
>
> int
> main() {
> short* p = new short(1) ;
>
> cout << "sizeof(short*): " << sizeof(short*) << endl ;
> cout << "p = " << p << endl ;
> cout << "set_addr(p,0x1): " << set_addr(p,0x1) << endl ;
> cout << "clear_addr(set_addr(p,0x2)): "
> << clear_addr(set_addr(p,0x2)) << endl ;
> }
> ////////////////////////////////////////////////
>
> g++ (version 4.0.1) won't compile this program on a 32 bit machine.
> It complained the 64 bit specialization: the "0xfffffffffffffffc" in
> the "clear" method is too large, and the "error" method is in error.
> But since on a 32 bit machine, only the 32 bit pointer template
> specialization is needed. It seems that g++ has looked both of them.
> Other compilers such as the Intel/Sun Workshop/SGI C++ compilers all
> compiled the above code without problem. I think they all didn't
> look at the 64 bit pointer template specialization.[/color]

Whether it is used/needed or not, all code must be valid. You cannot
have an integer constant outside the range of integers.
[color=blue]
>
> Is this behavior implementation dependent? Is there a way (a
> command-line option) to make g++ behave like others?? Or I cannot
> assume a lazy instantiation for the compiler?[/color]

You can only assume that valid code should compile.


You *can* form the unsigned long constant by using the complement
operator, like ~3UL. You cannot, however, assume that a pointer is of
the same size as an unsigned long, or that an unsigned long has 32 or
64 bits. That is also implementation dependent.


Bo Persson


benben
Guest
 
Posts: n/a
#3: Apr 2 '06

re: Template specialization problems


Yang Zhang wrote:[color=blue]
> I have a small program like this:
>
> ////////////////////////////////////////////////
> #include <iostream>
> using namespace std ;
>
> // set bits in an address
> template <typename T>
> inline T*
> set_addr(const T* addr, unsigned long n) {
> return (T*)( (unsigned long)addr | n) ;
> }
>
> // helper class that clears the last two bits of an address
> template <typename T, int S>
> struct clear_addr_helper {} ;
>
> // 32 bit pointer specialization
> template <typename T>
> struct clear_addr_helper<T,4> {
> static inline T*
> clear(const T* addr) {
> return (T*)( (unsigned long)addr & 0xfffffffc) ;
> }
> } ;
>[/color]

#ifdef USE_64_BIT // or whatever macro you have for the same effect
[color=blue]
> // 64 bit pointer specialization
> template <typename T>
> struct clear_addr_helper<T,8> {
> static inline T*
> clear(const T* addr) {
> return (T*)( (unsigned long)addr & 0xfffffffffffffffc) ;
> }
> // a function that won't compile
> static inline void
> error() { ss }
> } ;[/color]

#endif
[color=blue]
>
> template <typename T>
> inline T*
> clear_addr(const T* addr) {
> return clear_addr_helper<T,sizeof(T*)>::clear(addr) ;
> }
>
> int
> main() {
> short* p = new short(1) ;
>
> cout << "sizeof(short*): " << sizeof(short*) << endl ;
> cout << "p = " << p << endl ;
> cout << "set_addr(p,0x1): " << set_addr(p,0x1) << endl ;
> cout << "clear_addr(set_addr(p,0x2)): "
> << clear_addr(set_addr(p,0x2)) << endl ;
> }
> ////////////////////////////////////////////////
>
> g++ (version 4.0.1) won't compile this program on a 32 bit machine. It
> complained the 64 bit specialization: the "0xfffffffffffffffc" in the
> "clear" method is too large, and the "error" method is in error. But
> since on a 32 bit machine, only the 32 bit pointer template
> specialization is needed. It seems that g++ has looked both of them.
> Other compilers such as the Intel/Sun Workshop/SGI C++ compilers all
> compiled the above code without problem. I think they all didn't look at
> the 64 bit pointer template specialization.[/color]

Well, I think the error was reported early in the lexical analysis where
your 64bit address gets transformed into a token stored for later use.
So even if you don't instantiate the specialization you still get an error
[color=blue]
>
> Is this behavior implementation dependent? Is there a way (a
> command-line option) to make g++ behave like others?? Or I cannot assume
> a lazy instantiation for the compiler?[/color]

Notice the use of a preprocessor macro above. This is what i think the
most effective way.
[color=blue]
>
> Thanks in advance,
> --Yang[/color]

regards,
Ben
Closed Thread