Есть такая структура VARIANT (находится в OAIdl.h) у нее среди прочего есть огромное объединение, в котором сидит куча самых разнах форматов. Программа использует много функций, которые возвращают указатель на SAFEARRAY из этих структур. Причем, разные фумкции используют в VARIANT разные форматы. Есть вот такая функция для вытаскивания значений одного конкретного формата.
void ReadSafeArray (const SAFEARRAY *src,
std::vector<DWORD> & dest)
{
dest.clear ();
if (src != NULL)
{
ULONG items (0);
for (ULONG count = 0; count < src->cDims; count++)
{
items += src->rgsabound[count].cElements;
}
for (ULONG item = 0; item < items; item++)
{
dest.push_back ((((VARIANT *) src->pvData) + item)->lVal);
}
}
}
Поскольку фоматов множество, то хочется параметризировать функцию типом значения и считываемым членом объединения. И вот здесь я встал в тупик. Тип вектора, понятное дело; задается без проблем херез std::vector<T> А как задать считываемый член объединения? Т.е. как указать, что в выражении
(((VARIANT *) src->pvData) + item)->lVal
в одном случае надо брать lVal, в другом date, в третьем fltVal и т.д.? Пробовал через связку std::for_each и boost::bind. Работает, но выглядит очень запутанным. Может есть более простое решение?
Здравствуйте, KernelMode, Вы писали:
KM>Есть такая структура VARIANT (находится в OAIdl.h) у нее среди прочего есть огромное объединение, в котором сидит куча самых разнах форматов. Программа использует много функций, которые возвращают указатель на SAFEARRAY из этих структур. Причем, разные фумкции используют в VARIANT разные форматы. Есть вот такая функция для вытаскивания значений одного конкретного формата.
<skip>
KM>Поскольку фоматов множество, то хочется параметризировать функцию типом значения и считываемым членом объединения. И вот здесь я встал в тупик. Тип вектора, понятное дело; задается без проблем херез std::vector<T> А как задать считываемый член объединения? Т.е. как указать, что в выражении (((VARIANT *) src->pvData) + item)->lVal
в одном случае надо брать lVal, в другом date, в третьем fltVal и т.д.? Пробовал через связку std::for_each и boost::bind. Работает, но выглядит очень запутанным. Может есть более простое решение?
ну во первых я бы не стал передавать сюда контейнер... imho, более удобный способ передвать output iterator -- таким образом ты не навязываешь вызывающему тип контейнера (включая параметры которыми он инстанциирован... ну кто вот сказал что дефолтный аллокатор это хорошо во всех случаях)
чтобы решить проблему с выбором конкретного типа из объединения можно во-первыз передавать смещение до нужного поля как параметр (в т.ч. и шаблонный) в функцию... например так:
template <typename UnionMemberType, typename OutputIterator>
void ReadSafeArray (
const SAFEARRAY* src
, UnionMemberType VARIANT::* field
, OutputIterator it
)
{
if (src != NULL)
{
ULONG items(0);
// напрашивается std::count
for (ULONG count = 0; count < src->cDims; count++)
items += src->rgsabound[count].cElements;
for (ULONG item = 0; item < items; item++)
*it++ = ((((VARIANT *) src->pvData) + item)->*field)
}
}
также можно ассертнуть что value_type твоего итератора тотже что и UnionMemberType. (ну или последний приводится к первому)
если чуток извратицо и написать метафункцию (или traits) которая умеет маппировать UnionMemberType в имя поляны (смещение точнее) можно обойтись без параметра указателя на датамембер (ну количество типов хранимых в варианте заранее известно и ограничено ведь?)... тогда сигнатура станет еще проще:
template <typename OutputIterator>
void ReadSafeArray (
const SAFEARRAY* src
, OutputIterator it
)
{
...
}
т.е. тип который необходимо достать из обединения мы узнаем по value_type итератора...
Здравствуйте, KernelMode, Вы писали:
ATL::CComSafeArray может облегчить работу.
Здравствуйте, _nn_, Вы писали:
__>ATL::CComSafeArray может облегчить работу.
Он поддерживает далеко не все форматы, которые есть в VARIANT.