I'd like to map string to an instance member functions, and store each mapping in the map.
What is the clean way of doing something like that?
class MyClass
{
//........
virtual double GetX();
virtual double GetSomethingElse();
virtual double GetT();
virtual double GetRR();
//........
};
class Processor
{
private:
typedef double (MyClass::*MemFuncGetter)();
static map<std::string, MemFuncGetter> descrToFuncMap;
public:
static void Initialize();
void Process(Myclass m, string);
};
void Processor::Initialize()
{
descrToFuncMap["X"]=&MyClass::GetX;
descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
descrToFuncMap["RR"]=&MyClass::GetRR;
descrToFuncMap["T"]=&MyClass::GetT;
};
void Processor::Process(MyClass ms, const std::string& key)
{
map<std::string, Getter>::iterator found=descrToFuncMap.find(key);
if(found!=descrToFuncMap.end())
{
MemFuncGetter memFunc=found->second;
double dResult=(ms).*memFunc();
std::cout<<"Command="<<key<<", and result="<<result<<std::end;
}
}
let me know if you see a problem with this approach and what are common idioms for that?
Perhaps, I should use if-else-if statement chain, given that I have a limited number of member functions, instead of a confusing map of func pointers
BTW, I found some of the useful info here in the c++-faq-lite
-
I'd change
void Processor::Process(MyClass ms, std::string key)
to
void Processor::Process(const MyClass& ms, const std::string& key)
Don't see any bad side effect for now. Probably with boost::function as a map value it will be easier in the future.
Mykola Golubyev : Maps are ok for me. -
Looks fine to me, but for the fact that
descrToFuncMap
needs to be declaredstatic
if you intend to initialise it from inside the static functionInitialize()
.If you want to make sure that
Initialize()
gets called, and gets called just once, you can use the Singleton pattern. Basically, if you aren't doing multithreading, that just means wrappingdescrToFuncMap
inside its own class (called sayFuncMap
) with a private constructor that callsInitialize()
. Then you add astatic
local variable of typeFuncMap
toProcessor::Process()
-- because the variable isstatic
, it persists and is only initialised once.Example code (I now realise that
friend
isn't really necessary here):class Processor { private: typedef double (MyClass::*MemFuncGetter)(); class FuncMap { public: FuncMap() { descrToFuncMap["X"]=&MyClass::GetX; descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; descrToFuncMap["RR"]=&MyClass::GetRR; descrToFuncMap["T"]=&MyClass::GetT; } // Of course you could encapsulate this, but its hardly worth // the bother since the whole class is private anyway. map<std::string, MemFuncGetter> descrToFuncMap; }; public: void Process(Myclass m, string); }; void Processor::Process(MyClass ms, const std::string& key) { static FuncMap fm; // Only gets initialised on first call map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key); if(found!=fm.descrToFuncMap.end()) { MemFuncGetter memFunc=found->second; double dResult=(ms).*memFunc(); std::cout<<"Command="<<key<<", and result="<<result<<std::end; } }
This is not the "true" Singleton pattern as different functions could create their own, separate instances of
FuncMap
, but it's enough for what you need. For "true" Singleton, you would declareFuncMap
's constructor private and add a static method, saygetInstance()
, which defined the one-and-only instance as astatic
variable and returned a reference to that.Processor::Process()
would then use this withFuncMap& fm = FuncMap::getInstance();
-
Avoid using 'virtual' if you are using maps of function pointers. In this context, using 'virtual' keyword will not help much. For example
descrToFuncMap["X"]=&MyClass::GetX;
will always call 'MyClass::GetX' function even if GetX is overridden by the derived class of MyClass.
Usually you won't have large number of functions in class, rather than using map you can create simple struct array and use a for loop. If the number of functions are small, there won't be any big performance difference in map and array. Something similar to code below will work
class MyClass { //........ double GetX(); double GetSomethingElse(); double GetT(); double GetRR(); //........ }; typedef double (MyClass::*MemFuncGetter)(); struct FuncTable { const char* m_pFuncName; MemFuncGetter m_pFuncPtr; }; class Processor { public: void Process(Myclass& m, string); }; static FuncTable descrToFuncMap[] { { "X", &MyClass::GetX}, { "SomethingElse", &MyClass::GetSomethingElse }, { "RR", &MyClass::GetRR}, { "T", &MyClass::GetT} }; void Processor::Process(MyClass& ms, const std::string& key) { int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0]) for(int i=0; i< functablesize; ++i) { if( strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0) { MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr; double dResult=(ms).*memFunc(); std::cout<<"Command="<<key<<"result="<<result<<std::end; break; } } }
0 comments:
Post a Comment