Click here to Skip to main content
15,887,135 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I want to implement a template function that has different behaviour for POD types (double, int, char, etc.) as opposed to actual structs or class types that can have constructors and destructors.

I could solve this by providing a generic function for all types:
C++
template <class T> void alloc(T*& p, std::size_t size) {
   p = reinterpret_cast<T*> ( malloc(size*sizeof(T)) );
   new (p) T[size];
}
and then specialisations for all POD types:
C++
template <> void alloc(double*& p, std::size_t size) {
   p = reinterpret_cast<double*> ( malloc(size*sizeof(double)) );
}

However, I'd rather not copy/paste the same code all over again 6-8 times if I can avoid it.

So is there a better way to distinguish between POD types and others that doesn't force me to copy specializations all over again?

And before you ask, no, new and delete are not an option. I plan to implant my own memory manager here later. (and that will mean even more specalizations!)


P.S.:
For the sake of those wondering about the need for this in the view of some simple answers to the problem I outlined above:

The actual problems are more convoluted than the above example, including
- a class that passes on the template parameter through several function calls; therefore, even though the compiler does, I do not know the actual type at the point I call the allocator
- additional allocators that, among other things, provide the ability to pass an initializer value
- specializations for certain classes or even POD types (such as TCHAR) that need a particular treatment upon allocation or deallocation

The first issue is the most restricting one. The second I could cut down to whatever I can make work for now and expand later, if I find a solution. The last issue doesn't currently seem to be a problem in light of the question, but I haven't checked all cases yet.
Posted
Updated 28-Apr-11 23:53pm
v2
Comments
CPallini 29-Apr-11 5:33am    
Why do you need such specializations? Version 1 works for builtin types too.
Stefan_Lang 29-Apr-11 5:55am    
See my P.S. above, I don't know the types at 'coding time' and I need different code for passing on initializers.

I don't see why you would need to handle POD types differently. Their 'constructors' are no-ops, and your generic version of the function will expand to just a malloc call for POD types. Just like your second specialized version.
 
Share this answer
 
Comments
Stefan_Lang 29-Apr-11 5:23am    
That was what I wasn't sure of (i. e. constructors being no-ops). Is that true of destructors as well? If so you may be right.

I've planned to provide allocators with initializers though, in which case I still have to treat the initialization differently. Since the only common case for POD types would be 0-initialization though, I may be able to just provide a seperate function and be done with it.

Hm... I'll have to check my use cases...
Niklas L 29-Apr-11 5:28am    
Both constructors and destructors of POD types are no-ops. And you can use constructor semantics to initialize POD types as well. int a(0);
Olivier Levrey 29-Apr-11 5:36am    
Yes you are right Niklas. Unless Stefan wants to do something very specific, he shouldn't need to separate his templates.
Have a 5.
Stephan, I suggest you send my answer to trash and go on with Niklas's solution ;)
Stefan_Lang 29-Apr-11 5:39am    
No, not trash. The actual problems I face are quite a lot more involved than the simple example I gave, but I think between your ans Niklas' responses I will find a way. :-)
Stefan_Lang 29-Apr-11 5:37am    
I know I can construct a single POD type variable like that, but unfortunately not a whole array. I'd need to loop over the array and call placement new constructors for each individual element. Not that I can't do that but I hoped to boost performance a bit by using memset for POD types instead.
I see only one possibilty: using macros. But you will probably end up with a very dirty code...

By the way, I don't really understand your need. Template functions are supposed to do the same things for different types. If you want a different behaviour for differents types, then why use templates?

You could maybe write 2 template functions: one for class types, one for "POD" types.
 
Share this answer
 
v2
Comments
Stefan_Lang 29-Apr-11 5:05am    
Forgive me if I'm not exploding in enthusiasm at the suggestion. I'm supposed to refactor the code to something better, not obfuscate it. ;)
Olivier Levrey 29-Apr-11 5:06am    
I understand and I agree at 100% :)
I updated my answer. Not a genious idea, but probably better than using macros.
Stefan_Lang 29-Apr-11 5:15am    
Thanks, the update makes much more sense.

The problem is that the memory manager I have in fact *will* be the same code mostly, and the call to the actual allocation functions (which are similar to those above) will be hidden under a stack of templated functions that are the same for POD and non-POD types.

I will have to check how much of the code would need to be duplicated for your suggestion to work.
You can exclude a function from the overload set at compile using the SFINAE principle, e.g. an instantiation of this function template:

template< class T >
void alloc(T*& p, std::size_t s, 
 typename std::enable_if< std::is_pod< T >::value, void* >::type = 0)
{
 // do pod work here
}


would only be considered a valid overload if std::is_pod< T >::value is true at compile time.

Cheers,

Paul
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900