在 C++ 中输入 map

发布于 2024-10-16 02:06:01 字数 966 浏览 1 评论 0原文

我将从引出实际问题的背景开始。

我正在尝试构建一个类,其每个实例都将管理数据如何绑定到对象中。 该类最好包含方法:

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 此时只是一些标识符 - int ,不包含任何数据或方法(这不应更改)。上面使用的 DataType 基本上可以是任何类,但一般情况是这只是一个没有方法的结构体。可用作 DataType 的完整列表在编译时已知,但不应进行编码,因为它经常更改。

我试图实现的两个目标是: - 可维护性/速度 - 用户应该能够添加新的数据类型结构而无需修改此代码 - 速度 - 应该尽可能快:)

现在我迄今为止最好的想法是创建一个容器类:

class ContainerBase;

template<typename DataType>
class DataTypeContainer : ContainerBase;

那么数据结构将类似于:

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

那么如何才能实现这一目标? boost::mpl::map 有帮助吗?如何?

从本质上讲,这应该是可以做到的,因为所有数据类型在编译时都是已知的。

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). DataType used above can be basically any class, however the general situation is that this is just a struct with no methods. 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.

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 :)

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?

In essence this should be possible to do since all DataType's are known at compile time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

や莫失莫忘 2024-10-23 02:06:01
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;
    }
};

这段代码做了一些假设——比如对象类型的默认构造,并且它是可散列的。但修改起来应该不会太困难。如果您只需要与特定对象关联的每种类型的一个数据成员,那么获得定义的行为将变得更加棘手,因为您不能依赖 RTTI 为每种可能的数据类型返回唯一的名称。

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

吐个泡泡 2024-10-23 02:06:01

如果您想要从类型到值的 map 的等效项,并且它可以是全局的,则可以使用 static 成员:

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

加上 DataManager的适当定义。 ::this_type_map 用于 T 的各种值(但这些定义不需要位于同一源文件中)。之后,您可以使用 (void*)(new int) 创建类型映射对象,使用 delete (int*)(m) 释放它们,然后查找该对象对于使用 DataManager::this_type_map[m] 的实例 m 和类型 T。当然,您可能希望将它们包装在函数或对象中。请注意,您可以使用与 Object 不同的类型作为 map 中的值类型,包括(使用模板专业化)为类型中的每个键类型使用不同的值类型地图。

If you want the equivalent of a map from types to values, and it can be global, you can use static members:

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). 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]. 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.

私藏温柔 2024-10-23 02:06:01

我认为您需要 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 可以像这样实现:
https://github.com/alekstheod/tnnlib /blob/master/src/Utilities/Utilities/MPL/Tuple.h

I think that you need the std::tuple c++11 or playing with 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

素食主义者 2024-10-23 02:06:01

您可以使用类型之间的映射创建一个元组,如下所示:

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

然后指定要转换的函数

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

然后指定映射

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

,最后您可以调用转换函数并将任何类型转换为任何其他类型;)

请参阅我的文章:
https://cpptelepathy.wordpress.com/

您需要此文件
https://github.com/alekstheod/tnnlib/ blob/master/src/Utilities/MPL/Tuple.h

用于 util::get

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

See my article here:
https://cpptelepathy.wordpress.com/

You would need this file
https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/MPL/Tuple.h

for util::get

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文