Inserting member function pointers into the map
My question is a bit tricky, so I'll start with an example:
class a
{
public:
a()
{
pointerMap.insert(pair<std::string, void a::*(int, int)> ("func1", func1);
pointerMap.insert(pair<std::string, void a::*(int, int)> ("func2", func2);
}
private:
void func1(int a, int b);
void func2(int a, int b);
std::map<std::string, void a::* (int, int)> pointerMap;
}
My question is, is it the right thing to do this by adding member function pointers to the map inside the object so that you only refer to a single instance func1
or func2
?
Also, I don't know how I would like to call this function from a pointer. Would it be something like this?
map["func1"](2,4);
I am a little confused about the syntax when working with member functions.
source to share
Code first:
#include <map>
#include <string>
class a
{
public:
a()
{
pointerMap["func1"] = &a::func1;
pointerMap["func2"] = &a::func2;
}
void invoke(const std::string& name, int x, int y) {
if(pointerMap[name])
(this->*pointerMap[name])(x, y);
}
private:
void func1(int a, int b) {};
void func2(int a, int b) {};
std::map<std::string, void (a::*)(int, int)> pointerMap;
};
int main () {
a o;
o.invoke("func1", 1, 2);
}
Now, for your questions:
My question is if this is the correct way to add member function pointers to a map inside an object
I find the index operator is []
much easier to read than the insert you are inserting.
so that you only refer to a specific instance of func1 or func2.
An element pointer function does not have an associated instance. You bind a pointer to an instance when you call it. This way your map could be a static member just as easily.
how I would like to call this function from a pointer.
Syntax: (instance.*pointer)(args)
or (class_pointer->*pointer)(args)
. Since you didn't say which instance the functions should be invoked on, I assumed this
. Your pointers live on the map, so we have:
((this)->*(this->pointerMap["func1"]))(arg1, arg2)
or
(this->*pointerMap[name])(x, y);
source to share
It's kind of right. Maybe a typedef can make things cleaner:
typedef std::map<std::string, void(a::*)(int, int)> pfmap_type;
pfmap_type m; // ^^^^^^
// ...
m.insert(pfmap_type::value_type("hello", &a::func1));
// ^^^
(this->*(m["hello"]))(1, 2);
(this->*(m.find("hello")->second))(3, 4);
In fact, none of the access cards are a good idea, because you absolutely have to check that the card element exists, otherwise you have a bad pointer. So I recommend something like this:
void call(const char * key, int a, int b) const
{
pfmap_type::const_iterator it = m.find(key);
if (it != m.end()) { (this->*(it->second))(a, b); }
}
source to share
This is the correct way to insert pointers to a map, but you can tidy up a bit by using make_pair
which outputs you template arguments:
pointerMap.insert(std::make_pair("func1", &func1)); // The '&' is optional
To call the function, you need to use the operator .*
or ->*
, depending on whether the object you are calling it is a pointer or not:
a obj; // Regular object
(a .* map["func1")(2, 4); // Extra parens needed due to operator precedence
a *ptr; // Pointer
(a ->* map["func1")(2, 4);
Some people like to define a macro to make it more obvious what you are doing as the syntax can be a little confusing:
#define CALL_MEMBER_FUN_PTR(obj, fun) ((obj) ->* (fun))
...
a *ptr;
CALL_MEMBER_FUN_PTR(ptr, map["func1"])(2, 4);
source to share