提问人:Dirk Pitt 提问时间:10/13/2023 最后编辑:Dirk Pitt 更新时间:10/14/2023 访问量:100
C++ 虚拟模板函数最佳解决方法
C++ virtual template function best workaround
问:
我有一个类ComInterface,它有一个重载的函数send。对于许多不同的枚举类类型,此函数是重载的。
class ComInterface{
public:
virtual void send(MotorCommand cmd);
virtual void send(ValveCommand cmd);
virtual void send(ThrottleCommand cmd);
};
然后我有一个衍生类 CanCom
class CanCom: public ComInterface{
public:
void send(uint32_t CanID, uint8_t cmd);
virtual void send(MotorCommand cmd){
send(1, (uint8_t) cmd); //1 is the Motor specific address
}
virtual void send(ValveCommand cmd){
send(2, (uint8_t) cmd); //2 is the Valve specific address
}
virtual void send(ThrottleCommand cmd){
send(3, (uint8_t) cmd);
}
};
这是到目前为止的代码。由于我有许多这样的枚举类(如 MotorCommand),因此我更喜欢使用模板。像这样:
class ComInterface{
public:
template <typename T>
virtual void send(T cmd);
};
然后,将使用模板变量插入特定地址,如下所示 C++ 模板函数将参数类型与整数相关联 所以像 [正如链接问题中 Jarod42 提出的]
template <typename T>
constexpr uint32_t can_address = [](){ throw "Should be specialized"; }();
template <> constexpr uint32_t can_address<MotorCommand> = 1;
template <> constexpr uint32_t can_address<ValveCommand> = 2;
template <> constexpr uint32_t can_address<ThrottleCommand> = 3;
template <typename T> send(T cmd){
send(can_address<T>, (uint8_t) msg);
}
但是现在我遇到了一个问题,我不能使用模板和虚拟功能。经过一些研究,我认为解决这个问题的最佳方法是使用基于策略的设计。因此,ComInterface 是一个模板类,并且有一个类似于 CanImplementation 类的东西作为模板参数传递。不幸的是,这意味着 ComInterface 的类型必须在使用它的每个地方进行调整,这在我的情况下是不可能的。
我的下一个想法是创建一个新类“TypeToIDConverter”,它将类型转换为 ID。但是,必须再次将此类派生到“TypeToCanIDConverter”,并且由于它必须是虚拟的,因此不能使用任何模板。我考虑使用普通重写,然后将存储在 ComInterface 中的基类型转换器转换为具有 static_cast 的派生类。但是,我不确定这是否可行,这肯定是一个丑陋的解决方案!
我发现的其他想法是类型错误和访客原则。但是,我不确定我将如何在这里使用它们。
有没有一个优雅的解决方案?我不必为每个枚举类类型编写发送函数,而且还保持接口通用并为其他协议(如 LinCom 或 I2CCom)的新实现留出空间?
提前非常感谢!这个问题已经困扰了我好几天了......
答: 暂无答案
评论
void send(uint32_t CanID, uint8_t cmd);
ComInterface
virtual void send(CommandType command_type, int command_id)
where 不直接绑定到地址。实现会根据他们认为合适的方式将类型映射到地址。command_type
std::variant
struct ComInterface { virtual void send(uint32_t, uint8_t); template<typename T> void send(T cmd) { send(can_address<T>, (uint8_t) cmd); } };