C++ 虚拟模板函数最佳解决方法

C++ virtual template function best workaround

提问人:Dirk Pitt 提问时间:10/13/2023 最后编辑:Dirk Pitt 更新时间:10/14/2023 访问量:100

问:

我有一个类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)的新实现留出空间?

提前非常感谢!这个问题已经困扰了我好几天了......

C++ 模板 虚拟函数 基于策略的设计

评论

2赞 Igor Tandetnik 10/13/2023
在 中制作虚拟函数,并将非虚拟函数模板转发给它。void send(uint32_t CanID, uint8_t cmd);ComInterface
0赞 Dirk Pitt 10/13/2023
@IgorTandetnik我不确定我是否正确地理解了你。这意味着将类型转换为 CanID 的部分在 ComInterface 中是固定的,对吧?不幸的是,这不是一个选项,因为 ID 也必须特定于通信协议,例如 CanCom 与 LinCom 具有不同的 ID。
1赞 Igor Tandetnik 10/13/2023
virtual void send(CommandType command_type, int command_id)where 不直接绑定到地址。实现会根据他们认为合适的方式将类型映射到地址。command_type
3赞 HolyBlackCat 10/13/2023
您还可以使用所有枚举。std::variant
1赞 Raymond Chen 10/14/2023
@IgorTandetnik的意思是struct ComInterface { virtual void send(uint32_t, uint8_t); template<typename T> void send(T cmd) { send(can_address<T>, (uint8_t) cmd); } };

答: 暂无答案