Template parameter a pointer?

Started by
8 comments, last by Emmanuel Deloget 19 years, 6 months ago
Hey, I've been playing around with some templated stuff - a Serialiser similar to the one which is used in Enginuity I think. Normal types serialise properly, but I can't figure out a nice implementation for pointers. In particular, I have the SerialOp(T& object) templated function. Is there an easy way to determine at runtime whether the object is a pointer, without using RTTI? I was thinking of casting the object to a void*, and seeing if that wasn't 0, but I'm not so sure that it would fail for some objects, and can't find information on trying to cast ints to pointers or whatnot. Anywho, best case, would there be any way to exclude pointers from the generated template types [I'm guessing no], and secondly, is there any way to determine quickly and easily if a type is a pointer - would the void* cast work? //end rant CJM
Advertisement
The void* cast wont work. It will give you a compile-time error if the type isn't a pointer (using static_cast, however a C-style cast will let you do the cast with builtin types giving you some funky void* pointer), but that's the opposite of what you'd need to exclude pointers from being used as the template parameter.

I'm fairly sure you can't have code that does something like
if(isPointer) {...}
else {...}
so your only option would to be create a scenario that would force a compile-time error if the type is a pointer. To do this check out the boost::concept_check library.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
Actually, just thought of something.
template<typename I>void func(I test) {  std::cout << "A normal type!" << std::endl;}template<typename I>void func(I* test) {  std::cout << "A pointer type!" << std::endl;}int main() {  int i=1;  int *p=&i;  func(i);  func(p);  return 0;}

Works with gcc3.2.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
joanusdmentia,

I'm checking out the Concept Check Library thing you sent to me. I've already tried something like what you describe, but the problem with your second bit of code is that you've got pass by value. I'm using references to get the data into the function, and I'm relatively sure that pointer-to-reference isn't legal. Do you think that the easiest solution would just be then to use T* and T** and then dereference, which is basically equivelent?

CJM
There is an alternative, its called type traits, boost has a type traits package:

template < typename T >struct is_pointer {   enum { val = false };};template < typename T >struct is_pointer<T*> {   enum { val = true };};template < typename T >void SerialOp(const T& obj) {    if(is_pointer<T>::val) {          /* code to handle pointers */    } else {         /* normal code */    }}


compiler needs partial specialization support which VC++ 6.0 doesn't have.

notice i've used a constant reference, you should do the same
Hey snk_kid,

I think that's about as clean as it's gonna get. Thanks.

also, thanks joanusdmentia.

CJM
Quote:Original post by CJM
I'm using references to get the data into the function, and I'm relatively sure that pointer-to-reference isn't legal. Do you think that the easiest solution would just be then to use T* and T** and then dereference, which is basically equivelent?
CJM

Doesn't matter.
template<typename I>void func(const I& test) {  std::cout << "A normal type!" << std::endl;}template<typename I>void func(I* test) {  std::cout << "A pointer type!" << std::endl;}


But as snk_kid said, type traits would be better still. (can't believe I didn't think of that!)
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
And, to avoid generating unnecessary code (since T can't be both pointer type and normal type), you can do this:

template<bool> struct switch_t { };template<class T, bool B>void serialise(const T& a, switch_t<B>)    {    std::cout << "A normal type!" << std::endl;    }template<class T>void serialise(const T& a, switch_t<true>)    {    std::cout << "A pointer type!" << std::endl;    }template<class T>void SerialOp(const T& test)     {    serialise(test, switch_t<is_pointer<T>::val>());    }


This will only instantiate the code that actually gets executed.
Quote:Original post by roller
And, to avoid generating unnecessary code (since T can't be both pointer type and normal type), you can do this:

*** Source Snippet Removed ***

This will only instantiate the code that actually gets executed.


while i totally agree that this is a better method, the version i posted the if statement is trivially true or false at compile time thus if optimizations (maybe even then) are turned on i'm sure the compiler can easily eliminate the if statement using dead code elimination.
Quote:Original post by snk_kid

< snip >

compiler needs partial specialization support which VC++ 6.0 doesn't have.

notice i've used a constant reference, you should do the same


Hello,

Maybe this should do the trick (and it does not require partial specialisation AFAIK)

template <typename T> struct is_pointer{  static inline bool is(T*) {return true;}  static inline bool is(const T&) {return false;}};int _tmain(int argc, _TCHAR* argv[]){  int *pi=0;  int i=0;    if (is_pointer<int>::is(i))  {    std::cout << "i is a pointer" << std::endl;  }  else  {    std::cout << "i is NOT a pointer" << std::endl;  }  if (is_pointer<int>::is(pi))  {    std::cout << "pi is a pointer" << std::endl;  }  else  {    std::cout << "pi is NOT a pointer" << std::endl;  }  std::cin >> i;  return 0;}


Both VC6 and VC .NET 2003 release mode optimize out the not needed code.

(edit: added VC6 italic stuff ^_^ (this "i logout you while you are editing you post" is rather strange :/ Not sure it is by design...)

Regards,

[Edited by - Emmanuel Deloget on September 28, 2004 9:05:51 AM]

This topic is closed to new replies.

Advertisement