有可能在C++中有类的查找表吗

Is it possible to have lookup table of classes in C++?

本文关键字:查找 C++ 有可能      更新时间:2023-10-16

我有一个函数:

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());
}

有没有更优雅的解决方案?

这是一种标准的模板元编程技术:traits类型。我唯一要改变的是使用标准模板元编程习惯用法(type是类型trait的标准名称,而不是classname(,并避免让trait指定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());
}

通过这种方式,贴图是从Maya阵列类型到基本元素类型。这使您可以自由地创建到除vector之外的其他类型的映射。你可以创建一个std::arraystd::list或任何你喜欢的东西。此外,如果您想更改vector的分配器类型,您可以自由更改,这与您的原始代码不同。

有更优雅的解决方案吗?

我建议。。。

给定一个简单的模板类型列表容器

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>>;

使用lookForTypelookForType_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>, "!" );
}