Home > Mobile >  How to create a map with key of string and value a pointer to a member function
How to create a map with key of string and value a pointer to a member function

Time:09-22

I want to create a map whose key is a string and whose value is one of the member functions of a class. I originally had the functions outside the class and that could be called from a function in the class.

void nvmRead(unsigned char* msg, unsigned char* resp_frame);
void nvmWrite(unsigned char* msg, unsigned char* resp_frame);
void nvmProvision(unsigned char* msg, unsigned char* resp_frame);
void nvmStatus(unsigned char* msg, unsigned char* resp_frame);

std::map<std::string, void (*)(unsigned char* msg, unsigned char* resp_frame)> command_table = {
  { "NVM_READ", nvmRead },
  { "NVM_WRITE", nvmWrite },
  { "NVM_PROVISION", nvmProvision },
  { "NVM_STATUS", nvmStatus }
};

Then from a function in my class that receives a command request corresponding to one of the keys in the s variable it jumps to the appropriate function. I call the function using:

command_table.at(s)(parm1, parm2);

That got me to the appropriate function when they were defined external to the class.

I am trying to do the same thing but I want the above functions to be within the class, so that it can access private members of the class.

If I move the above lines of code into the class in the public section it seems to complain about not being able to convert the functions:

 error: could not convert '{{"NVM_READ", ((myns::RaidDevCommInTask*)this)->myns::RaidDevCommInTask::nvmRead}, {"NVM_WRITE", ((myns::RaidDevCommInTask*)this)->myns::RaidDevCommInTask::nvmWrite}, {"NVM_PROVISION", ((myns::RaidDevCommInTask*)this)->myns::RaidDevCommInTask::nvmProvision}, {"NVM_STATUS", ((myna::RaidDevCommInTask*)this)->myns::RaidDevCommInTask::nvmStatus}}' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basic_string<char>, void (*)(unsigned char*, unsigned char*)>'
   85 |   };

I have tried various combinations that I won't go into here. Including making the assignments in a constructor doing something along the lines of

command_table["NVM_READ"] = nvmRead

which generates this error:

src/tests/raid_dev_comm_in_task.cpp:40:31: error: cannot convert 'myns::RaidDevCommInTask::nvmRead' from type 'void (myns::RaidDevCommInTask::)(unsigned char*, unsigned char*)' to type 'std::map<std::__cxx11::basic_string<char>, void (*)(unsigned char*, unsigned char*)>::mapped_type' {aka 'void (*)(unsigned char*, unsigned char*)'}
   40 |   command_table["NVM_READ"] = nvmRead;
      |                               ^~~~~~~

Again trying lots of different combinations that I won't go into here.

I can't seem to find the correct combination.

How can I make a map where a string is used as the key and the value is a class' member function within the class?

CodePudding user response:

Instead of simple function pointers, you could store pointers-to-member-functions. Note that the syntax for calling them is a bit different, since they require an object to work on:

using MemFnT = void(RaidDevCommInTask::*)(unsigned char*, unsigned char*);
std::map<std::string, MemFnT> command_table = {
  { "NVM_READ", &RaidDevCommInTask::nvmRead },
  { "NVM_WRITE", &RaidDevCommInTask::nvmWrite },
  { "NVM_PROVISION", &RaidDevCommInTask::nvmProvision },
  { "NVM_STATUS", &RaidDevCommInTask::nvmStatus }
};

Then when you call them, you'll do something like:

MemFnT command = command_table.at(s);
(this->*command)(param1, param2);

CodePudding user response:

You could make a lookup table of member functions:

struct RaidDevCommInTask {

    void call(std::string cmd, unsigned char* msg, unsigned char* resp_frame) {
        static std::unordered_map<std::string,
          void(RaidDevCommInTask::*)(unsigned char*, unsigned char*)> command_table
        {
            { "NVM_READ", &RaidDevCommInTask::nvmRead },
            { "NVM_WRITE",  &RaidDevCommInTask::nvmWrite },
            { "NVM_PROVISION", &RaidDevCommInTask::nvmProvision},
            { "NVM_STATUS", &RaidDevCommInTask::nvmStatus }
        };

        // call the found member function:        
        (this->*command_table.at(cmd))(msg, resp_frame);
    }

private:
    void nvmRead(unsigned char*, unsigned char*){}
    void nvmWrite(unsigned char*, unsigned char*){}
    void nvmProvision(unsigned char*, unsigned char*){}
    void nvmStatus(unsigned char*, unsigned char*){}
};

If you need the map accessible from other functions, make it static to the class instead of inside call.

CodePudding user response:

If you can use C 11, the simplest answer would be to use std::bind and std::function.

Something like this:

void nvmRead(unsigned char* msg, unsigned char* resp_frame);
void nvmWrite(unsigned char* msg, unsigned char* resp_frame);
void nvmProvision(unsigned char* msg, unsigned char* resp_frame);
void nvmStatus(unsigned char* msg, unsigned char* resp_frame);

std::map<std::string, std::function<void(unsigned char*, unsigned char*)>> command_table = {
  { "NVM_READ", std::bind(&RaidDevCommInTask::nvmRead, this, _1, _2) },
  { "NVM_WRITE", std::bind(&RaidDevCommInTask::nvmWrite, this, _1, _2) },
  { "NVM_PROVISION", std::bind(&RaidDevCommInTask::nvmProvision, this, _1, _2) },
  { "NVM_STATUS", std::bind(&RaidDevCommInTask::nvmStatus, this, _1, _2) }
};

Note that this creates an instance of command_table for each instance of the class, which is often undesirable.

Also, std::function can be more expensive, so if you need performance, it'd be better just to have something like:

enum class Command {
    NVM_READ,
    NVM_WRITE,
    NVM_PROVISION,
    NVM_STATUS,
};

static std::map<std::string, Command> command_table = {
  { "NVM_READ", Command::NVM_READ },
  { "NVM_WRITE", Command::NVM_WRITE },
  { "NVM_PROVISION", Command::NVM_PROVISION },
  { "NVM_STATUS", Command::NVM_STATUS },
};

void nvmCommand(const std::string& command, unsigned char* msg, unsigned char* resp_frame)
{
    switch (command)
    {
    case Command::NVM_READ:
        return nvmRead(msg, resp_frame);
    case Command::NVM_WRITE:
        /* ... */
    }
}
  •  Tags:  
  • c
  • Related