Template specialization problems

Y

Yang Zhang

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
 
B

Bo Persson

Yang Zhang said:
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.

Whether it is used/needed or not, all code must be valid. You cannot
have an integer constant outside the range of integers.
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?

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
 
B

benben

Yang said:
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) ;
}
} ;

#ifdef USE_64_BIT // or whatever macro you have for the same effect
// 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 }
} ;
#endif


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.

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
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?

Notice the use of a preprocessor macro above. This is what i think the
most effective way.
Thanks in advance,
--Yang

regards,
Ben
 

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,780
Messages
2,569,611
Members
45,271
Latest member
BuyAtenaLabsCBD

Latest Threads

Top