Возможно ли иметь таблицу поиска классов в C ++? - PullRequest
3 голосов
/ 10 ноября 2019

У меня есть функция:

template <class T, class Array>
void DumpArrayDebug(Array& out, const T& source)

Предполагается, что она будет использоваться для выгрузки данных из классов массивов в Maya (приложение Autodesk) в обычный вектор. Пример таких типов массивов:

MFloatArray;
MColorArray;
MIntArray;

Эти классы имеют одинаковый интерфейс, но не имеют базового класса. В настоящее время я использую эту функцию следующим образом:

MFloatArray someInternalMayaFloatData;
...
std::vector<float> buffer;
DumpArrayDebug(buffer, someInternalMayaFloatData);

Глядя на этот код, я задаюсь вопросом: можно ли как-то связать 2 класса внутри шаблона через что-то вроде таблицы поиска? Таким образом, этот результат должен выглядеть примерно так:

template <class T>
void dumpArrayDbg(const T& source, ClassLookupTable<T>& out)

До сих пор я мог придумать следующее чудовище:

template <typename T>
struct ClassLookupTable
{
    T classname;
};

template <>
struct ClassLookupTable<MIntArray>
{
    std::vector<int> classname;
};

template <>
struct ClassLookupTable<MFloatArray>
{
    std::vector<float> classname;
};

template <>
struct ClassLookupTable<MColorArray>
{
    std::vector<MColor> classname;
};

template <class T>
void dumpArrayDbg(const T& source, decltype(ClassLookupTable<T>::classname)& out)
{
    int length = source.length();
    out.clear();
    out.resize(length);
    source.get(out.data());
}

Есть ли более элегантное решение?

Ответы [ 2 ]

3 голосов
/ 10 ноября 2019

Это стандартная методика метапрограммирования шаблонов: тип черт. Единственное, что я хотел бы изменить, - это использовать стандартные идиомы метапрограммирования шаблонов (type - это стандартное имя для черты типа, а не classname) и избегать указания черты vector:

template <typename T>
struct MayaArrayBaseElementTrait; //The primary template should never be used.

template <>
struct MayaArrayBaseElementTrait<MIntArray>
{
    using type = int;
};

template <>
struct MayaArrayBaseElementTrait<MFloatArray>
{
    using type = float;
};

template <>
struct MayaArrayBaseElementTrait<MColorArray>
{
    using type = MColor;
};

template<typename T>
using MayaArrayBaseElementTrait_t = typename MayaArrayBaseElementTrait<T>::type;


template <class T>
void dumpArrayDbg(const T& source, std::vector<MayaArrayBaseElementTrait_t<T>>& out)
{
    int length = source.length();
    out.clear();
    out.resize(length);
    source.get(out.data());
}

ThisКстати, отображение происходит от типа массива Maya к базовому типу элемента. Это дает вам свободу создавать сопоставления другим типам, кроме vector. Вы можете создать std::array или std::list или что угодно. Кроме того, если вы когда-нибудь захотите изменить тип распределителя для vector, вы можете сделать это в отличие от исходного кода.

2 голосов
/ 10 ноября 2019

Есть ли более элегантное решение?

Я предлагаю следующее ...

Учитывая простой контейнер списка типов шаблонов

template <typename ...>
struct typeList
 { };

и рекурсивный шаблон следующим образом

template <typename, typename>
struct lookForType
 { };

template <typename T, typename V, typename ... Ts>
struct lookForType<T, typeList<T, V, Ts...>>
 { using type = V; };

template <typename T, typename U, typename V, typename ... Ts>
struct lookForType<T, typeList<U, V, Ts...>>
   : lookForType<T, typeList<Ts...>>
 { };

с помощником using для упрощения извлечения type

template <typename T, typename L>
using lookForType_t = typename lookForType<T, L>::type;

вы можете создать отображение следующим образом

using myList = typeList<MIntArray,   std::vector<int>,
                        MFloatArray, std::vector<float>,
                        MColorArray, std::vector<Color>>;

и получите требуемый тип, используя lookForType или lookForType_t

using l1 = lookForType_t<MIntArray,   myList>;

Ниже приведен полный пример компиляции

#include <vector>
#include <type_traits>

template <typename ...>
struct typeList
 { };

template <typename, typename>
struct lookForType
 { };

template <typename T, typename V, typename ... Ts>
struct lookForType<T, typeList<T, V, Ts...>>
 { using type = V; };

template <typename T, typename U, typename V, typename ... Ts>
struct lookForType<T, typeList<U, V, Ts...>>
   : lookForType<T, typeList<Ts...>>
 { };

template <typename T, typename L>
using lookForType_t = typename lookForType<T, L>::type;

struct Color       {};
struct MFloatArray {};
struct MColorArray {};
struct MIntArray   {};

int main()
 {
   using myList = typeList<MIntArray,   std::vector<int>,
                           MFloatArray, std::vector<float>,
                           MColorArray, std::vector<Color>>;

   using l1 = lookForType_t<MIntArray,   myList>;
   using l2 = lookForType_t<MFloatArray, myList>;
   using l3 = lookForType_t<MColorArray, myList>;


   static_assert( std::is_same_v<std::vector<int>,   l1>, "!" );
   static_assert( std::is_same_v<std::vector<float>, l2>, "!" );
   static_assert( std::is_same_v<std::vector<Color>, l3>, "!" );
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...