Сопоставление типов COM VARIANT с реальными типами с использованием карты - PullRequest
0 голосов
/ 01 сентября 2010

Я пишу оболочку COM для объекта COM, который отправляет различные типы значений от клиента и хочет сопоставить эти типы в Map с их фактическим типом C ++, таким как VT_BSTR, с wstring и т. Д.

Я думал о том, чтобы определить перечисление всех типов COM-вариантов, а затем использовать карту, чтобы использовать этот Enum в качестве ключа и фактический тип, содержащий извлеченное значение, однако я сталкиваюсь с проблемой, которую не могу найти глобальный тип для размещения на моей карте, который я могу привести к строковому или двойному типу или тому, что мне вручают для размещения на карте.

Возможно, мои мысли о том, как это сделать, совершенно неверны, пожалуйста, совет?

Я думал о пустом указателе, однако кажется, что компилятору не нравятся мои приведения:

(пример)

    enum Type
    {
        VT_INTEGER=0,
        VT_DBL=1

    };


    map<Type, void*> typemap;
    typedef pair<Type, void*> m_typepair;
    typemap.insert( m_typepair(VT_INTEGER, 0));
    typemap.insert( m_typepair(VT_DBL, (double)2.5));  // it does not like this cast

    map<Type, void*>::iterator m_typeiter;

Для итерации этой карты, вероятно, потребуется оператор switch внутри, чтобы найти правильный тип, я не уверен, что есть лучший способ?

Ответы [ 3 ]

1 голос
/ 01 сентября 2010

Не уверен, что вы пытаетесь сделать, это, безусловно, звучит неправильно. ВАРИАНТ, который вы получаете от клиента, должен быть преобразован в тип, с которым вы знаете, как иметь дело. Это легко сделать, просто вызовите функцию VariantToXxxx (). Например, используйте VariantToString (), если вы хотите получить строку.

Уже есть несколько классов-оболочек C ++, которые облегчают эту задачу. _variant_t, CComVariant, COleVariant. Все они делают одно и то же, просто разные файлы #include. _variant_t хорош, потому что он не привязывает вас ни к MFC, ни к ATL. Если вы уже не используете их. Их метод ChangeType () выполняет преобразование. Управление памятью автоматическое.

0 голосов
/ 01 сентября 2010

Вам известно о _variant_t ? Возможно, вы изобретаете колесо. В нем есть все соответствующие constrcutors и перегруженные назначения. То есть _variant_t var = 0.0 работает как положено (VT_R8)

0 голосов
/ 01 сентября 2010

Я обычно использую шаблонную специализацию для такого рода задач. У меня есть функция шаблона, которая преобразует из типа варианта в тип C ++, который выглядит следующим образом:

template <typename T>
T variantToCpp(const Variant&);

template <>
int variantToCpp<int>(const Variant& v)
{
  // Check that v really contains an int, if not, you can silently fail or throw an exception
  // Get and return the int
}

template <>
std::wstring variantToCpp<std::wstring>(const Variant& v)
{
  // Check that v really contains a string, if not, you can silently fail or throw an exception
  // Get and return the string
}

// etc. for each C++ type

// Usage
int i = variantToCpp<int>(someVariantIGotViaCOM);

Таким образом, вы получаете постоянное преобразование Variant в тип C ++. Также обратите внимание, что шаблонная функция по умолчанию не имеет тела - она ​​вызовет ошибку компоновщика (в большинстве компиляторов), если кто-то попытается использовать преобразование для неспециализированного типа.

Аналогичным образом вы можете выполнить преобразование из типа C ++ в вариант:

template <typename T>
Variant cppToVariant(T);

template <>
Variant cppToVariant<int>(int val)
{
  // Convert to variant and return it
}

// etc. for each type

// Usage:
int i = 10;
Variant var = cppToVariant(i);  // You don't even need to explicitly specify the type here, the compiler deduces it

Если вы настаиваете на использовании карты и множества ifs для этого вида конверсии, вы можете использовать указатель void *, вам просто нужно инициализировать его указателем на тип:

int *myInteger = new int; *myInteger = 42;
double *myDouble = new double; *myDouble = 42;
typemap.insert( m_typepair(VT_INTEGER, myInteger));
typemap.insert( m_typepair(VT_DBL, myDouble));
// Don't forget to free them when you clear the map

Если вас не устраивает ни одно из вышеперечисленных решений, возможно, стоит посмотреть boost :: any .

...