简体   繁体   English

在C ++中输入地图

[英]Type map in C++

I'll begin with a context that will lead to the actual question. 我将从一个导致实际问题的上下文开始。

I'm trying to build a class whose every instance will manage how data is tied together into objects. 我正在尝试建立一个类,其每个实例将管理如何将数据绑定到对象中。 The class should preferably contain methods: 该类最好包含方法:

class DataManager {
  Object CreateObject();
  void DestoryObject();

  template<typename DataType>
  DataType* AddDataToObject(Object o)

  template<typename DataType>
  DataType* GetDataForObject(Object o)

  template<typename DataType>
  void RemoveDataFromObject(Object o)
};

Object in the code above is just some identifier - int at this point and does not contain any data or methods (this should not change). 上面代码中的对象只是一些标识符-此时为int,不包含任何数据或方法(这不应更改)。 DataType used above can be basically any class, however the general situation is that this is just a struct with no methods. 上面使用的DataType基本上可以是任何类,但是一般情况是这只是一个没有方法的结构。 The complete list of things that can be used as DataType is known at compile time but should not be encoded as it changes quite often. 可以用作DataType的事物的完整列表在编译时是已知的,但不应进行编码,因为它经常更改。

The two goals I try to achieve are: - Maintainability/Speed - The user should be able to add new DataType structures without modifying this code - Speed - should be as fast as possible :) 我尝试实现的两个目标是:-可维护性/速度-用户应该能够在不修改此代码的情况下添加新的DataType结构-速度-应该尽可能快:)

Now the best thing idea I had so far is to make a container classes: 现在,到目前为止,我最好的想法是创建一个容器类:

class ContainerBase;

template<typename DataType>
class DataTypeContainer : ContainerBase;

The data structure then would be something like: 数据结构将类似于:

map< DataTypeType, map< Object, ContainerBase* > >

Sow how can one achieve this? 母猪怎么能做到这一点? Would boost::mpl::map help and how? 会对boost :: mpl :: map帮助有帮助吗?

In essence this should be possible to do since all DataType's are known at compile time. 从本质上讲,应该可以这样做,因为所有DataType在编译时都是已知的。

I think that you need the std::tuple c++11 or playing with boost::tuple for c++ 03 我认为您需要std :: tuple c ++ 11或使用boost :: tuple for c ++ 03

template<typename T>
struct Entry{
  T t;
};

int main(int argc, char **argv) {
  std::tuple< int, float, double, Entry<int> > objects;
  std::get<0>(objects) = 3;
  std::get<3>(objects).t = 5;

  //
  utils::get< Entry<int> >(object).t = 5;
  return 0;
}

get by type can be implemented like here: https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/MPL/Tuple.h 按类型获取可以像下面这样实现: https : //github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/MPL/Tuple.h

You could create a tuple with the mapping between your types like that: 您可以使用以下类型之间的映射创建一个元组:

template < std::size_t sz, typename... Types >
struct TypeMap {
    TypeMap (std::array< std::tuple< Types... >, sz > m) : mapping (m) {
    }

    std::array< std::tuple< Types... >, sz > mapping;
};

Then specify a function to convert 然后指定一个要转换的函数

template < typename To, typename From, std::size_t sz, typename... T >
To convert (From from, TypeMap< sz, T... > m) {
    for (auto entry : m.mapping) {
        if (utils::get< From > (entry) == from) {
            return utils::get< To > (entry); //Tricky part here
        }
    }

    throw std::logic_error ("No entry in the typemap");
}

Then specify the mapping 然后指定映射

const auto map = TypeMap{{std::make_tuple (red, "red", 1), 
                          std::make_tuple (green, "green", 2),
                          std::make_tuple (blue, "blue", 3)}};

and finally you can call your convert function and convert any type to any other type ;) 最后,您可以调用您的convert函数并将任何类型转换为任何其他类型;)

See my article here: https://cpptelepathy.wordpress.com/ 在这里查看我的文章: https : //cpptelepathy.wordpress.com/

You would need this file https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/MPL/Tuple.h 您将需要此文件https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/MPL/Tuple.h

for util::get 对于util :: get

class DataManager {
    struct internal_base { virtual ~internal_base() {} };
    template<typename T> struct internal_data : public internal_base {
        T t;
    };
    boost::unordered_map<Object, boost::unordered_map<std::string, boost::unique_ptr<internal_base>>> data;
public:
    Object CreateObject() { return Object(); }
    void DestroyObject(Object o) { data.erase(o); }

    template<typename DataType> DataType* AddDataToObject(Object o, std::string name) {
        internal_data<T>* ptr = new internal_data<T>();
        data[o][name] = ptr;
        return &ptr->t;
    }

    template<typename DataType> DataType* GetDataForObject(Object o, std::string name) {
        internal_base* ptr = data[o][name].get();
        if (internal_data<DataType>* dptr = dynamic_cast<internal_data<DataType>*>(ptr)) {
            return &dptr->t;
        else
            return 0;
    }

    void RemoveDataFromObject(Object o, std::string name) {
        data[o][name] = 0;
    }
};

This code makes some assumptions- like default-construction of Object type, and that it is hashable. 这段代码做出了一些假设,例如Object类型的默认构造,并且它是可哈希的。 But it shouldn't be too difficult to modify. 但是修改起来应该不会太困难。 It would be substantially trickier to get defined behaviour if you want just one data member of each type associated with a specific Object, because you can't rely on RTTI to return unique names for each possible DataType. 如果只希望与特定对象关联的每种类型的一个数据成员,则要获得定义的行为将非常困难,因为您不能依赖RTTI为每种可能的DataType返回唯一的名称。

If you want the equivalent of a map from types to values, and it can be global, you can use static members: 如果要等效于从类型到值的map ,并且它可以是全局的,则可以使用static成员:

template <typename T>
struct DataManager {
  static std::map<void*, Object> this_type_map;
};

plus appropriate definitions of DataManager<T>::this_type_map for the various values of T (but those definitions don't need to be in the same source file). 加的适当的定义DataManager<T>::this_type_map为的各种值T (但这些定义并不需要是相同的源文件中)。 After that, you can create type map objects using (void*)(new int) , free them using delete (int*)(m) , and look up the object for an instance m and a type T using DataManager<T>::this_type_map[m] . 之后,您可以使用(void*)(new int)创建类型映射对象,使用delete (int*)(m)释放它们,并使用DataManager<T>::this_type_map[m]查找对象m和类型T的对象DataManager<T>::this_type_map[m] You would want to wrap these in functions or objects, of course. 当然,您可能希望将它们包装在函数或对象中。 Note that you can have a different type than Object as the value type in the map , including (using template specializations) having a different value type for each key type in the type map. 请注意, map的值类型可以具有与Object不同的类型,包括(使用模板特殊化)类型映射中的每种键类型都具有不同的值类型。

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

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