C++访问者模式模板函数无法重载的问题解决

2022-07-19,,,,

目录
  • 背景
  • 解决方案
  • 最终代码

背景

最近遇到一个比较棘手的场景,我们有一堆模块,他们有一个通用的基类,我们不防假设为 baseclass,该类有一些通用的结构以及需要重载的方法。这些模块有一个堆同名但是不同类型

参数的方法,比如:

int derivedclass1::donlptask(const derivedreq1& req, derivedresp* resp);

类似这样的。每个 derivedclass 的donlptask都是同名不同参数的,而且这些要给业务去具体实现。正常来说,很容易想到函数重载的方式,但是很不幸,模板函数无法重载
但是,我们想让框架层和业务层相对解耦,不想让业务的具体类型等污染框架调度模块的结构。

解决方案

在这里,我们利用访问者模式的思想,结合c++的模板来统一处理。先定义一个visitor,该类定义好具体业务模块的通用操作步骤;实现的时候利用模板特化来实例化不同的业务模块及其donlptask 函数。这样在框架层只需要调用visitor 的统一模板接口即可,具体参看一下代码。

最终代码

#include <iostream>
#include <type_traits>

// 以下模拟请求协议 =====================
class basereq {};

class derivedreq : public basereq {};

class baseresp {};

class derivedresp : public baseresp {};

derivedreq g_derived_req;

// 以下模拟 nlp ============================

class baseclass {
 public:
  // 单纯视为一个需要重载的函数
  virtual int get_field_id() = 0;
     
  virtual void wormup () {}
};

#define register_prototype(req_type, resp_type) \
 public:                                        \
  using reqtype = req_type;                     \
  using resptype = resp_type;

class derivedclass : public baseclass {
  // 注册请求类型
  register_prototype(derivedreq, derivedresp)
 public:
  int donlptask(const derivedreq&, derivedresp* resp) {
    std::cout << "derived donlptask\n";
  }

  int get_field_id() override { return 1; }
};

// 以下模拟pb反射 =========================
const basereq* getreqtype() { return &g_derived_req; }

// 以下是 visitor 的定义 ===========
class visitor {
 public:
  template <typename classtype>
  int dovisit(classtype* base) {
    static_assert(std::is_base_of<baseclass, derivedclass>::value,
                  "type failed");
    int idx = base->get_field_id();
    std::cout << "visitor get field_id " << idx << std::endl;
    const auto* req = getmessagetype<typename classtype::reqtype>(getreqtype());
    typename classtype::resptype resp;
    // 返回计算结果
    return base->donlptask(*req, &resp);
  }

 private:
  template <typename reqtype>
  const reqtype* getmessagetype(const basereq* req) {
    static_assert(std::is_base_of<basereq, reqtype>::value,
                  "message type error");
    return static_cast<const reqtype*>(req);
  }
};

int main() {
  derivedclass dc;
  visitor vis;
  vis.dovisit(&dc);
  return 0;
}

到此这篇关于c++访问者模式模板函数无法重载的问题解决的文章就介绍到这了,更多相关c++模板函数无法重载内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

《C++访问者模式模板函数无法重载的问题解决.doc》

下载本文的Word格式文档,以方便收藏与打印。