C++;从编译时多态性中隐藏模板习惯用法 我正在编写一个C++硬件抽象层(HAL),它需要尽可能快。p>

C++;从编译时多态性中隐藏模板习惯用法 我正在编写一个C++硬件抽象层(HAL),它需要尽可能快。p>,c++,templates,polymorphic-associations,c++03,C++,Templates,Polymorphic Associations,C++03,多态性提供了最好的API,但虚拟表查找确实会降低代码的速度 这导致我将模板与策略结合使用,以获得编译时多态性。但是,由于具有不同参数的模板被实例化为完全不同的类型,我不能在函数调用中互换使用它们,除非函数也是模板 但是,我不想强制HAL库的用户将所有函数都作为模板编写,因为我使用了模板 为了便于说明,假设这是我的HAL: template<typename T_POLICY> class I2CManager { public: void send(uint8_t

多态性提供了最好的API,但虚拟表查找确实会降低代码的速度

这导致我将模板与策略结合使用,以获得编译时多态性。但是,由于具有不同参数的模板被实例化为完全不同的类型,我不能在函数调用中互换使用它们,除非函数也是模板

但是,我不想强制HAL库的用户将所有函数都作为模板编写,因为我使用了模板

为了便于说明,假设这是我的HAL:

template<typename T_POLICY>
class I2CManager {
public:     
    void send(uint8_t data) {
        T_POLICY::send(data);
        ++sent_data; 
    }
private:
    int sent_data; // Just to illustrate that I2CManager has state
};

class I2C1 {
    static void send(uint8_t data) { /* Run some code here */ }
};

class I2C2 {
    static void send(uint8_t data) { /* Run other code here */ }
};


// OTHER HW
template<typename T_POLICY>
class UARTManager { ··· };

class UART1 { ··· };
class UART2 { ··· };

template<typename T_POLICY>
class TIMERManager { ··· };

class TIMER1A { ··· };
class TIMER1B { ··· };
模板
I2C级经理{
公众:
无效发送(uint8_t数据){
T_策略::发送(数据);
++发送数据;
}
私人:
int sent_data;//只是为了说明I2CManager具有状态
};
I2C1类{
静态void发送(uint8_t data){/*在此处运行一些代码*/}
};
I2C2类{
静态void发送(uint8_t data){/*在此处运行其他代码*/}
};
//其他硬件
模板
类UARTManager{···};
类UART1{···};
UART2类{···};
模板
类TIMERManager{···};
班级时间1A{··};
类时间1b{··};
这是可行的,我现在可以创建一个具有不同策略的I2CManager,如下所示。我甚至可以让几个i2cmanager同时运行不同的策略

I2CManager<I2C1> i2c1;
I2CManager<I2C2> i2c2;

i2c1.send(0x11); // This works
i2c2.send(0x11); // This also works
I2CManager i2c1;
I2C经理i2c2;
i2c1.发送(0x11);//这很有效
i2c2.发送(0x11);//这同样有效
现在,i2c1和i2c2拥有相同的公共方法,但它们不能互换。因此,我的HAL库的用户也被迫使用模板

// THIS DOES NOT WORK
void foo(I2CManager m) { m.send(0x11); }
foo(my_manager_1);

// BUT THIS WORKS
template<typename T>
void foo(I2CManager<T> m) { m.send(0x11); }
foo(i2c1);
//这不起作用
voidfoo(i2cm){m.send(0x11);}
foo(我的大学经理1);
//但这是有效的
模板
voidfoo(i2cm){m.send(0x11);}
foo(i2c1);

我是否可以以某种方式获得编译时多态性,但允许最终用户将其视为正常多态性?为了提高速度,我不在乎库中的内部代码是否变得难看或难以阅读,但API必须尽可能简单直观。

实际上,我希望foo()对不同的参数进行专门化(并在代码中复制),就像它是一个模板一样,但我不希望库的用户注意到它是一个模板函数。模板的替代品也很受欢迎

我不知道这是不是可能,但是我已经读到了一些概念,这些概念将出现在下一个C++标准中。我想要编译时多态性,但要像运行时多态性一样方便用户


注意事项:

  • 因为我正在连接硬件,我的硬件管理器的每个实例 不同的政策将是唯一的(即只有一个 HWManager实例和一个HWManager实例, 可能同时存在,也可能不同时存在)

  • 库将所有实例创建为全局变量,并且 无法治愈

  • 所有策略方法都非常短,因此具有多个唯一的 由于模板而产生的实例对于 为了提高执行速度

  • 代码大小并不重要(对于嵌入式系统来说是如此),但RAM的使用情况很重要 而执行速度确实如此。我需要尽可能多的问题来解决 在编译时。再说一次,我愿意有一个过度膨胀 可执行文件,以避免运行时解析

  • 最多只支持C++03


代码示例已编辑

所有实例都是由库作为全局变量创建的,并且不可治疗

你的意思是这样的,对吗

static HWManager<DrierPolicy> drierManager;

static HWManager<FridgePolicy> fridgeManager;
然后

因为我正在与硬件接口,所以具有不同策略的硬件管理器的每个实例化都是唯一的

那么为什么要将doStuff方法实现为实例方法呢?有些静态方法还不够好吗


(这些是问题,不是批评。是的,我知道,这几乎不是答案——虽然可能是答案——但我需要评论中没有提供的额外格式)

不是真的。混合编译时和运行时多态性通常是不可能的。您可以尝试使用
boost::variant
作为模板实例类型的参数。如果您知道编译期间的所有类型。基本上,您不能将编译时和运行时多线程混合使用,因为特定方法的模板实例化数量是无限的。您可以为HWManager提供某种默认策略。@xaxxon编译器不知道这一点。当您知道所涉及的全部类型时,您可以玩一些游戏。您可以为所有模板化类型创建一个公共基类型,然后创建您自己的、伪造的动态类型,但该类型不是基于vtable,而是基于您在对象中输入的信息(如int)。然后,用户可以对实际涉及的类型伪造动态强制转换,然后基于静态分派调用该函数。clang和v8 javascript引擎都使用这种类型的不可vtable rtti。以这种方式调用该方法时,没有额外的间接层。单面注释,您确定需要如此多的速度,以至于必须删除vtables引入的额外间接层吗?我这样问是因为I2C总线与uC速度相比非常慢(在快速模式下最大400 kHz)。也许你在别的地方遇到了瓶颈?也许这是一个过早优化的问题?所有的策略实际上都是一堆捆绑的静态方法。但管理者有私人变量(因此也有状态)。尽管如此,管理器的每个实例化都是唯一的,因为即使我有两个冰箱,它们也会有不同的策略(由于不同的配置向量)。此外,根据他们管理的特定硬件类型,我有不同的硬件管理器(我将在que中对此进行更新)
drierManager.doStuff();

fridgeManager.doStuff();