简体   繁体   English

如何使用c ++中的映射实现模板的返回类型查找?

[英]How do I implement return type lookup for templates using a map in c++?

I have two arrays. 我有两个数组。 One containing pointers to a base class. 一个包含指向基类的指针。 The other containing an Enum whose values give pointers as to the real type. 另一个包含一个Enum,其值表示实际类型。

I would now like to have a function that can get me an array with those entries that have a certain Enum value associated with them and return that array with the correct return type. 我现在想要一个函数,它可以为我提供一个数组,其中包含与它们相关联的某个枚举值的条目,并返回具有正确返回类型的数组。

Example (semi pseudocode): 示例(半伪代码):

std::array<BaseType, 2> a = { TypeAInstance, TypeBInstance };
std::array<TypeEnum, 2> b = { TypeA, TypeB };

template<typename SearchType>
std::array<SearchType*, 2> GetEntriesOfType()
{
  std::array<SearchType*, 2> ret;
  for(int i = 0; i < 2; i++) 
  {
    ret[i] = nullptr;
    if(b[i] == EnumForType(SearchType)) ret[i] = a[i];
  }
}

However I do not know of anyway to construct the EnumForType function or the reverse TypeForEnum function which would allow me to declare the template return type using: 但是我无论如何都不知道构造EnumForType函数或反向TypeForEnum函数,它允许我使用以下方法声明模板返回类型:

template<SearchTypeEnum>
TypeForEnum(SearchTypeEnum) GetEntriesOfType();

I would like to define such a constexpr function if possible. 如果可能的话,我想定义这样一个constexpr函数。

The underlying problem is that I have an array of Plugins that I iterate over. 根本问题是我有一个迭代的插件数组。 Where each plugin needs to be handled differently depending on the type. 每个插件需要根据类型进行不同的处理。 However since the type is runtime dependent and I can't have dynamic allocation (embedded system constraints) I store all Plugins in a fixed prereserved memory space. 但是,由于类型是运行时相关的,我无法进行动态分配(嵌入式系统约束),因此我将所有插件存储在固定的预留存储空间中。 I need to somehow cast the pointer to the base class to its correct type during runtime and handle it accordingly. 我需要在运行时以某种方式将指向基类的指针转换为正确的类型并相应地处理它。

This GetEntriesOfType function is supposed to make that more convenient. 这个GetEntriesOfType函数应该更方便。 I could of course get both arrays and then do a switch statement while iterating over both but I wanted to simplify that to the end user of that library. 我当然可以获得两个数组,然后在迭代时执行switch语句,但我想将其简化为该库的最终用户。

One way is to map each class type to an enumerator value: 一种方法是将每个类类型映射到枚举器值:

class A;
class B;

enum class Types {
    A,
    B
};

template<class T> struct EnumForType;

template<> struct EnumForType<A> { static constexpr Types value = Types::A; };
template<> struct EnumForType<B> { static constexpr Types value = Types::B; };

int main() {
    auto a = EnumForType<A>::value;
    auto b = EnumForType<B>::value;
}

You would use it like: 您会像以下一样使用它:

if(b[i] == EnumForType<SearchType>::value)

Instead of a enum, you could create an id for each type. 您可以为每种类型创建一个id,而不是枚举。

Let's define this id for a type with templates. 让我们具有模板的类型定义此id Since you prefer constexpr, RTTI is not a option. 由于您更喜欢constexpr,因此不能选择RTTI。 Here's what I do when I want a type id: 这是我想要一个类型ID时的工作:

template<typename>
void type_id() {}

using type_id_t = void(*)();

This is as simple as that. 这很简单。 Each instanciated function will ahve a different address, and the address of the function will always be the same for a given type under the as if rule. 每个instanciated函数都将使用不同的地址,并且对于as if规则下的给定类型,函数的地址将始终相同。

Then, adding you metadata is pretty easy. 然后,添加元数据非常简单。 We could define your array of plugin like this: 我们可以像这样定义你的插件数组:

std::array<std::pair<type_id_t, BaseType*>, 2> a = {
    std::make_pair(type_id<TypeA>, typeAInstance),
    std::make_pair(type_id<TypeB>, typeBInstance)
};

With that, you just associated a instance with a value that identify the type. 有了它,您只需将实例与标识该类型的值相关联。 Your GetEntriesOfType become trivial to implement: 您的GetEntriesOfType实现GetEntriesOfType很简单:

template<typename SearchType>
std::array<SearchType*, 2> GetEntriesOfType() {
    std::array<SearchType*, 2> ret;

    for(int i = 0; i < 2; i++) {
        ret[i] = nullptr;
        if(a[i].first == &type_id<SearchType>) ret[i] = a[i].second;
    }
}

I usually avoid to associate type with enums, as enums are not meant to represent type, but to map to simple integral values. 我通常避免将类型与枚举关联,因为枚举不是要表示类型,而是映射到简单的整数值。

Plus, if your array is constexpr, you could even return an array with only the right size to fit all instance of the SearchType instead of filling other values with nullptr . 另外,如果您的数组是constexpr,您甚至可以返回一个只有适当大小的数组来适应SearchType所有实例,而不是使用nullptr填充其他值。

The core ingredient to map an enumeration (or an integer) to a type is full specialization of something. 将枚举(或整数)映射到类型的核心要素是某些东西的完全特化。 For example, you could have 例如,你可以拥有

template <TypeEnum> struct EnumToType;
template <> struct EnumToType<TypeA> { using type = TypeAType; };
template <> struct EnumToType<TypeB> { using type = TypeBType; };
// ...

... and then use that appropriately in your function, eg (this assumes that BaseType is actually a pointer type; if it is not, the values are sliced when creating the array and the concrete type cannot be recovered portably): ...然后在你的函数中适当地使用它,例如(假设BaseType实际上是一个指针类型;如果不是,则在创建数组时切片值,并且无法移植恢复具体类型):

std::array<BaseType, 2> a = { TypeAInstance, TypeBInstance };
std::array<TypeEnum, 2> b = { TypeA, TypeB };

template<SearchTypeEnum E>
std::array<typename EnumToType<E>::type*, 2> GetEntriesOfType() {
    std::array<typename EnumToType<E>::type*, 2> rc;
    for (int i = 0; i != 2; ++i) {
        rc[i] = a[i] == E? static_cast<typename EnumToType<E>::type*>(b[i]);
    }
    return rc;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM