在我的真实代码中,我正在解析一系列作为连续消息的字节。消息头中的整数决定解释字节的适当方式
为了简化 SO,假设如下:
1
表示使用 struct MsgA
2
表示使用 struct MsgB
3
表示使用 struct MsgC
同样对于 SO 假设一个类,
NamePrinter
负责:
MsgA
、MsgB
或MsgC
之一)我知道如何为此编写代码。我还知道如何将
NamePrinter
与另一个对消息执行操作的类进行切换。我不知道该怎么做是选择在更一般的情况下调用NamePrinter
(或另一个类)的哪个成员函数
#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;
}
我想知道的是我是否可以用我选择的任意成员函数替换
onMsgPrintName
中的 intToPrintName
。注释掉的代码显示了尝试执行此操作但无法编译
添加另一个间接级别 - 一个知道如何调用任何对象上的特定方法的包装器。沿着
的路线class OnMsgPrintNameCaller {
template <typename Param, typename Obj, typename... Args>
static auto Call(Obj&& obj, Args&&... args) {
return std::forward<Obj>(obj).template onMsgPrintName<Param>(
std::forward<Args>(args)...);
}
};
还有类似的课程
onMsgPrintSomethingElse
。现在将其作为额外参数传递给 intToPrintName
:
template <typename MethodCaller, typename T>
void intToPrintName(const T& a_caller, const int a_id) {
switch (a_id) {
case MsgA::getId(): MethodCaller::template Call<MsgA>(a_caller); break;
// ...
}
}