I have some functions that I use to convert a 2D variant SAFEARRAY into various STL containers, kinda like so (illustrative only)
template<typename T>
std::set<T> SetFromSafeArray(VARIANT srcArray)
{
CComSafeArray<T> srcComArray(srcArray.parray);
std::set<T> destContainer;
for (ULONG i=0;i<srcComArray.GetCount();++i)
destContainer.insert(srcComArray.GetAt(i));
return destContainer;
}
I feel it's not a very c++-ish way of going about it and it means there's a separate function for each STL container I convert to.
My idea was to write a wrapper and custom iterator for CComSafeArrays so I could just do...
std::copy(srcComArray.begin(), srcComArray.end(), destContainer.begin());
but having never written an iterator before and being a novice I really don't know if it will be easy.
Is a custom CComSafeArray iterator my best, standard c++ like, option (in which case I'm sure I can find a good tutorial on writing an iterator)? Or is there some other way of going about it?
Boost is not an option.
TIA
My idea was to write a wrapper and custom iterator for CComSafeArrays
This is very good idea for creating iterator, but you don't need a wrapper around CComSafeArray<T>
, only iterator is needed.
so I could just do...
std::copy(srcComArray.begin(), srcComArray.end(), destContainer.begin());
But instead of doing your way, you can do this:
SomeContainer<T> destContainer(begin(srcComArray), end(srcComArray));
Because almost every STL container has constructor from range (pair of iterators).
Assuming you have written iterator over CComSafeArray<T>
- functions begin/end will be like these:
template <typename T>
CComSafeArrayIterator<T> begin(CComSafeArray<T>& container)
{
return CComSafeArrayIterator<T>(container, 0);
}
template <typename T>
CComSafeArrayIterator<T> end(CComSafeArray<T>& container)
{
return CComSafeArrayIterator<T>(container, container.getSize());
}
Notice that begin() is zero position, end() is getSize() position.
And writing an iterator is not rocket science. Just a few functions. The most important is to know what you need to iterate. In your case: the container reference(pointer) and the current position. Iterating is just moving the position. Accessing is via container and position. Comparing is via comparing position.
template <typename T>
class CComSafeArrayIterator {
public:
CComSafeArrayIterator(CComSafeArray<T>& container, ULONG position)
: container(&container),
position(position)
{}
// prefix ++it
CComSafeArrayIterator& operator ++() { ++position; return *this; }
// postfix it++
CComSafeArrayIterator operator ++(int) {
CComSafeArrayIterator prev = *this;
++position;
return prev;
}
// access by ->: it-> !! ony if getAt return reference not value
const T* operator -> () const {
return &(container->getAt(position));
}
// access by *: *it
const T& operator * () const {
return container->getAt(position);
}
// comparing
friend bool operator == (const CComSafeArrayIterator<T>& l,
const CComSafeArrayIterator<T>& r)
{
return l.position == r.position;
}
friend bool operator != (const CComSafeArrayIterator<T>& l,
const CComSafeArrayIterator<T>& r)
{
return l.position != r.position;
}
private:
// this is what you need
CComSafeArray<T>* container;
ULONG position;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With