Iterating through collection of different types in C++
Situation
I have a template class TIppImage<T>
for image of type T
. I have singleton class CIppMemoryManager
which can store a number of images of different size and type.
class CIppMemoryManager
{
public:
/// ... Singleton interface ...
template<class T> TIppImage<T>* GetImage(width, height);
private:
CIppMemoryManager();
~CIppMemoryManager();
std::map<IppDataType, void*> m_Containers;
};
IppDataType
is enum, which values correspond to actual types. All management is done in template class TIppImageContainer<T>
. And all specialization of this class is stored in m_Containers
as a void*
. It's not very good, but it is at least simple.
With this approach, I can simply implement template GetImage
method like this:
template<class T> TIppImage<T>* CIppMemoryManager::GetImage(width, height)
{
return reinterpret_cast<TIppImageContainer<T>*>(m_Containers[
TIppTypeTraits<T>::ipp_data_type])->GetImage(width, height);
}
where I'm using traits class TIppTypeTraits<T>
to obtain enum value from given type.
Problem
I cannot simply implement non-template methods like constructor. I need to explicitly handle all possible types:
CIppMemoryManager::CIppMemoryManager()
{
m_Containers[ipp8u] = new CIppImageContainer<Ipp8u>;
m_Containers[ipp8s] = new CIppImageContainer<Ipp8s>;
m_Containers[ipp16u] = new CIppImageContainer<Ipp16u>;
m_Containers[ipp16s] = new CIppImageContainer<Ipp16s>;
...
}
Worse, for destructor I also need to deal with void*
:
CIppMemoryManager::~CIppMemoryManager()
{
delete reinterpret_cast开发者_StackOverflow中文版<TIppImageContainer<Ipp8u>*>(m_Containers[ipp8u]);
delete reinterpret_cast<TIppImageContainer<Ipp8s>*>(m_Containers[ipp8s]);
delete reinterpret_cast<TIppImageContainer<Ipp16u>*>(m_Containers[ipp16u]);
delete reinterpret_cast<TIppImageContainer<Ipp16s>*>(m_Containers[ipp16s]);
...
}
So, the questions are:
a) Is there some way to iterate through collection of different types? Cannot use traits class here since function is non-template.
b) Is there some better way to store collection of containers - objects of different type? When they are just a different specialization of common template class, containers itself are pretty simple.
I think the class variant from the boost library (boost::variant
) may help you. You can use visitors to execute the appropriate code depending on the type stored in a variant. A std::vector<boost::variant<T0, T1,...>>
can store a list of objects of different types.
As your objects are similar, they may have the same size in memory, which is a good thing since boost::variant
storage is stack-based (no heap allocation - this is faster).
What's wrong with polymorphic CIppImageContainer<T>
(make them all share a common base class) and a smart pointer ?
Or some kind of boost::variant
?
boost::mpl::for_each
is tailor-made for that job. Define a vector of types to operate on, a functor or lambda expression to do something, and you are done.
boost::variant
is the most likely candidate but sometimes variant
S become rather large as they require some extra storage and also have to deal with alignment. So maybe boost::any
has advantages in some situations as well:
std::vector<std::pair< Type, boost::any > > data;
To comfortably iterate over such a container is harder (boost::transform_iterator
cannot have more than one return type, so this wont work without some template trickery).
精彩评论