In my real code I am parsing a series of bytes that are consecutive messages. An integer in a message header determines what is the appropriate way to interpret the bytes
To simplify for SO assume the following:
1means usestruct MsgA2means usestruct MsgB3means usestruct MsgC- Any other value is invalid
Also for SO assume that a class, NamePrinter is responsible for:
- Receiving a type (one of
MsgA,MsgB, orMsgC) - Instantiating that type
- Calling some methods of that type (just one method in the code below for the sake of example)
I know how to write code for this. I also know how to switch out NamePrinter with another class that also performs actions on messages. What I do not do not know how to do is chose which member function of NamePrinter (or another class) to call in a more general case
#include <iostream>
// Some made up "message" structs
struct MsgA final {
static constexpr int getId() { return 1; }
const char* getName() const { return "MsgA"; }
const char* getSomethingElse() const { return "SomethingElseA"; }
};
struct MsgB final {
static constexpr int getId() { return 2; }
const char* getName() const { return "MsgB"; }
const char* getSomethingElse() const { return "SomethingElseB"; }
};
struct MsgC final {
static constexpr int getId() { return 3; }
const char* getName() const { return "MsgC"; }
const char* getSomethingElse() const { return "SomethingElseC"; }
};
// A class that creates a "message" and performs and action on it
class NamePrinter final {
public:
template <class T>
void onMsgPrintName() const {
T t;
std::cout << t.getName() << std::endl;
}
template <class T>
void onMsgPrintSomethingElse() const {
T t;
std::cout << t.getSomethingElse() << std::endl;
}
};
// A function that can convert an integer into a "message" at compile time but
// is hardcoded to call onMsgPrintName
template <class T>
void intToPrintName(const T& a_caller, const int a_id) {
switch (a_id) {
case MsgA::getId(): a_caller.template onMsgPrintName<MsgA>(); break;
case MsgB::getId(): a_caller.template onMsgPrintName<MsgB>(); break;
case MsgC::getId(): a_caller.template onMsgPrintName<MsgC>(); break;
default:
std::cout << "Runtime error" << std::endl;
}
}
// This is invalid but tries to convey that onMsgPrintName has been replaced
// with a template
//template <class F, class T>
//void intToFunc(const T& a_caller, const int a_id) {
// switch (a_id) {
// case MsgA::getId(): a_caller.template F<MsgA>(); break;
// case MsgB::getId(): a_caller.template F<MsgB>(); break;
// case MsgC::getId(): a_caller.template F<MsgC>(); break;
// default:
// std::cout << "Runtime error" << std::endl;
// }
//}
int main(int argc, char** argv) {
const NamePrinter np;
// This will end up calling NamePrinter::onMsgPrintName
intToPrintName(np, argc);
// I want something like this that allows me to pick what is called
//intToFunc<NamePrinter::onMsgPrintName >(np, argc);
//intToFunc<NamePrinter::onMsgPrintSomethingElse>(np, argc);
return 0;
}
What I would like to know is if I can replace onMsgPrintName inside of intToPrintName with an arbitrary member function of my choice. The commented out code shows an attempt to do this which does not compile
Add another level of indirection - a wrapper that knows how to call a particular method on any object. Along the lines of
And similar class for
onMsgPrintSomethingElse. Now pass this as an extra parameter tointToPrintName:Usage: