在两个略有不同的std :: map

时间:2015-05-07 08:18:15

标签: c++ casting stl callback stdmap


我有一个std :: map定义如下:

typedef void (SomeClass::*callback_f)();

typedef std::pair<std::string, callback_f> my_pair;

typedef std::map<char,my_pair> my_map1;

这些定义有多个,所以有my_map1,my_map2等,并且它们中的每一个都与SomeClass类不同,后者是SomeClass,SomeClassTwo等。


我需要将所有这些地图传递给单个函数,无论地图如何,都必须有一个单一的签名,所以我定义了一个通用的地图:

typedef std::pair<std::string ,void(*)(void)> my_generic_pair;
typedef std::map<char, my_generic_pair> my_generic_map;

一个将其作为参数的函数:

void myGenericFunction(my_generic_map lmap);

myGenericFunction 不会真正使用回调,但使用 my_map {$ i}中的其他两个值,i = 1 ... n


问题是无论我试图在两个地图之间施放多么努力,编译器(符合C ++ 11的GCC)总是抱怨。


非常感谢任何想法。

3 个答案:

答案 0 :(得分:3)

如果您需要将所有地图传递给单个函数,那么所有地图必须完全相同(但您已经知道了)。

进行一些重新设计可以给你你想要的东西。

不是定义地图以保存特定的函数指针签名,而是简单地定义一个包含多态可调用对象的地图类型 - 这样的对象是std :: function&lt;&gt;。

完全可编译的示例(记得启用c ++ 11):

#include <iostream>
#include <functional>
#include <utility>
#include <string>
#include <map>

// callback_f is any callable that takes no parameters
typedef std::function<void()> callback_f;
typedef std::pair<std::string, callback_f> my_pair;

typedef std::map<char,my_pair> universal_map;

using namespace std;

struct SomeClass {
    static void callme_for_all() {
        cout << "SomeClass Hears You";
    }
};

struct SomeOtherClass {
    SomeOtherClass(string name)
    : _name { move(name) }
    {}

    void callme_for_each() const {
        cout << "I am called " << _name;
    }

private:
    string _name;    
};

void handle_map(const universal_map& m) {
    for (const auto& item : m) {
        cout << item.first << ":" << item.second.first << ":";
        item.second.second();
        cout << endl;
    }
}

int main()
{
   cout << "Hello World" << endl; 

   SomeClass a,b,c;

   SomeOtherClass x { "x" }, y { "y" }, z { "z" };

   universal_map map_someclass {
       { 'A', { "chicken", std::bind(&SomeClass::callme_for_all) } },
       { 'B', { "donkey", std::bind(&SomeClass::callme_for_all) } },
       { 'C', { "turkey", std::bind(&SomeClass::callme_for_all) } },
   };

   universal_map map_someotherclass {
       { 'A', { "pig", std::bind(&SomeOtherClass::callme_for_each, &x) } },
       { 'B', { "cat", std::bind(&SomeOtherClass::callme_for_each, &y) } },
       { 'C', { "dog", std::bind(&SomeOtherClass::callme_for_each, &z) } },
   };

   cout << "map for SomeClass - calling static methods" << endl;
   handle_map(map_someclass);
   cout << endl;

   cout << "map for SomeOtherClass - calling instance methods" << endl;
   handle_map(map_someotherclass);

   return 0;
}

答案 1 :(得分:1)

解决方案1:

template<typename T>
void myGenericFunction(std::map < char, std::pair < std::string, T > > lmap);

解决方案2(仅当您因任何原因无法使用模板和重载时):

enum MapType {MY_MAP1, MY_MAP2, ...};
void myGenericFunction(void* lmap, MapType typeOfLmap)
{
    switch(typeOfLmap)
    {
        case MY_MAP1:
            //do something with ((my_map1*)lmap)
            break;
        ...
    }
}

编辑:根据@TonyD的建议进行编辑。

答案 2 :(得分:1)

如果你可以控制SomeClass,SomeClass2 ......,你可以使用继承来解决这个问题:

class BaseClass
{
public:
  virtual ~BaseClass(){}
  virtual void f() = 0;
};
class SomeClass : public BaseClass {...};
class SomeClass2 : public BaseClass {...};

typedef void (BaseClass::*callback_f)();
....