Reputation: 2498
I have a template class which looks like the following:
template <template <class TypeT> class PoolT=pool_base>
struct pool_map
{
public:
template <typename U> struct pool { typedef PoolT<U> type };
public:
template <typename T, size_t S=sizeof(T)>
T& get( size_t index );
private:
pool<uint8_t>::type pool8_;
pool<uint16_t>::type pool16_;
pool<uint32_t>::type pool32_;
pool<uint64_t>::type pool64_;
};
template <template <class TypeT> class PoolT>
template <typename T, size_t S>
inline
T& pool_map<PoolT>::get( size_t index )
{
// Default case
}
template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,8>( size_t index )
{
// Dispatch to pool8_
}
template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,16>( size_t index )
{
// Dispatch to pool16_
}
template <template <class TypeT> class PoolT>
template <typename T>
inline
T& pool_map<PoolT>::get<T,32>( size_t index )
{
// Dispatch to pool32_
}
You obviously noticed that I wrote what would be possible in a wonderful and ideal world where default template parameters and partial specialization of template methods are possible (without specializing the entire class).
I would like to ear about advices to achieve the same effect, that is, being able to have a specialized method for each size S so that I can select the proper pool to use. I tried to add a get_pool<size_t>
inside the pool_map, but almost the same problem happens: i can't specialize the inner class without specializing the outer one...
The only solution that comes to my mind, would be to use an outer get_pool<size_t>
class that would take the pool_map as parameters an returns a reference to the poolX_
member, but I would like to avoid it, since it does not seems to be "the real static way".
Thanks for reading!
Upvotes: 3
Views: 688
Reputation: 299760
One solution is the use of enable_if
and disable_if
(normally) though I haven't tested it.
Another solution is to simply forward the implementation details to a helper:
namespace helper
{
template <class T> struct getter { static void Do() {} };
// specializations by type
}
template <class T>
T& pool_map<T>::get(size_t index) { return helper::getter<T>::Do(); }
Upvotes: 0
Reputation: 4892
There is one easy solution (maybe you didn't think about it), which is:
template <typename T>
T& pool_map<PoolT>::get( size_t index )
{
if (sizeof(T) * CHAR_BIT == 8) {
// Dispatch to pool8_
} else if (sizeof(T) * CHAR_BIT == 16) {
// Dispatch to pool16_
} else if (...) {
...
} else {
// Default case
}
}
But since this will maybe give you compilation errors (depending on what you put instead of "dispatch to ...") you could simply overload the get() function.
template <typename T>
typename std::enable_if<sizeof(T) * CHAR_BIT == 8,T>::type&
get( size_t index )
{
...
}
template <typename T>
typename std::enable_if<sizeof(T) * CHAR_BIT == 16,T>::type&
get( size_t index )
{
...
}
etc.
The only problem is that the default implementation (if you need any) needs a condition like sizeof(T) * CHAR_BIT != 8 && sizeof(T) * CHAR_BIT != 16 && sizeof(T) * CHAR_BIT != 32 && sizeof(T) * CHAR_BIT != 64
The last solution (the best one I'd say) would still to use a private class with a static function which you can specialize (what you said was not the "real static way")
Upvotes: 3