【问题标题】:C++: Templating a virtual method with different return typesC++:用不同的返回类型模板化一个虚方法
【发布时间】:2016-03-07 20:44:33
【问题描述】:

我正在尝试编写一个包含几个非常相似的虚拟方法的基类,我希望使用模板来减少重复:

class CPU {
    template<typename T>
    T getRegister(unsigned int which) {
        /** Returns value of specified register.
         */
        return *(T*)this->getRegisters()[which].data;
    };
    virtual  int16_t getRegister(unsigned int which);
    virtual uint16_t getRegister(unsigned int which);
    virtual  int32_t getRegister(unsigned int which);
    virtual uint32_t getRegister(unsigned int which);
    //etc...
};

class Z80: public CPU: { ... };
Z80 myCPU;
printf("Register 0 = 0x%04X\n", myCPU.getRegister<uint16_t>(0));

目标是让各个 CPU 能够定义自己的 getRegister() 或使用在 CPU 基类中定义的那个。

如果可能的话,我不确定正确的语法是什么?

与我找到的大多数答案不同的关键点:

  • 类本身不是模板
  • 方法是虚拟的

【问题讨论】:

  • 你不能有(虚拟)重载,唯一的区别是返回类型。
  • 不同名字怎么办?我可以在不重复实现的情况下提供 getRegister() 或 getRegister_uint32_t() 吗?

标签: c++ class templates template-specialization virtual-functions


【解决方案1】:

我去寻找一个副本,但找不到一个...我确定有一个,但我输入的内容都找不到。

C++ 不允许具有相同签名 [1] 的两个函数具有不同的返回类型。编译器需要直接从函数签名中知道返回类型。

有几种不同的方法可以解决这种特殊情况:

1) 声明不同的函数:

 virtual  int16_t getRegisterS16(unsigned int which);
 virtual uint16_t getRegisterU16(unsigned int which);
 virtual  int32_t getRegisterS32(unsigned int which);
 virtual uint32_t getRegisterU32(unsigned int which);

2) 使用间接类型:

virtual void getRegister(unsigned int which, int16_t &value);
virtual void getRegisterU16(unsigned int which, uint16_t &value);
...

3) 使用模板为 CPU 设置固定的寄存器大小:

template<typename T>
class CPU {
    T getRegister(unsigned int which) {
      ... 
    }
};

我还要在这里指出,对于 99% 的 CPU 操作,有符号和无符号数学是相同的。它只是比较不同的操作[至少在相当现代的 CPU 中,您可以期望在现代 x86 或 ARM 处理器上执行数学运算,而不是在简单的数学步骤中单独模拟每个位]

[1] 签名是名称、参数类型和成员函数,无论它是否是const - 我认为可能还有一两件事,但这些是主要的。

【讨论】:

  • 我可以在不重复函数的实际代码的情况下执行 #1 吗?即使用模板创建几个具有不同名称的类似方法?
  • 不确定。它们之间实际上有什么不同 - 您始终可以创建一个基本函数,将寄存器号 whichstatic_cast 获取到正确的类型。在编写 CPU 模拟器的整个方案中,这只是一小部分代码。
  • (我的简单 CPU 模拟器大约有 2300 行,但这包括一个简单的汇编程序以及模拟器本身 - 但它仅适用于我自己发明的单一 CPU 类型,这真的很简单模拟)
  • 这是一个调试接口,不是实际模拟器的一部分。区别就像上面显示的那样,转换为各种类型。我主要是想保持代码量小。
  • 好吧,为什么不总是返回 32 位值 - 或者总是知道寄存器大小,就像我的第三个示例一样 [您仍然可以始终将 CPU 寄存器存储为 32 位或 64 位整数]
猜你喜欢
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多