使用模板选择调用哪个模板化成员函数

问题描述 投票:0回答:1

在我的真实代码中,我正在解析一系列作为连续消息的字节。消息头中的整数决定解释字节的适当方式

为了简化 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
。注释掉的代码显示了尝试执行此操作但无法编译

c++ templates member-functions
1个回答
0
投票

添加另一个间接级别 - 一个知道如何调用任何对象上的特定方法的包装器。沿着

的路线
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;
    // ...
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.