C ++隐藏编译时多态性

时间:2016-09-19 10:14:26

标签: c++ templates polymorphic-associations c++03

我正在编写一个C ++硬件抽象层(HAL),它需要尽可能快。

多态性提供了最好的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 { ··· };

这有效,我现在可以使用不同的策略创建一个I2CManager,如下所示。我甚至可以让几个I2CManagers同时运行不同的策略。

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

i2c1.send(0x11); // This works
i2c2.send(0x11); // This also works

现在, 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);

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

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

我不知道这是否可能,但我已经阅读了一些关于 concepts 的内容,这些内容将出现在下一个C ++标准中。我想要编译时多态,但作为运行时多态性的用户友好。

考虑:

  • 因为我正在连接HW,我的HWManagers的每个实例都有 不同的政策将是独特的(即只有一个 HWManager实例和一个HWManager实例, 并且可能同时存在,也可能不存在。)

  • 所有实例都由库创建为全局变量,并且是 不可堆积。

  • 所有政策方法都非常短,因此具有多种独特性 模板的实例优于虚拟表 执行速度。

  • 代码大小无关紧要(适用于嵌入式系统),但RAM使用情况 和执行速度。我需要尽可能多地解决 在编译期间。再一次,我愿意过度膨胀 可执行文件,以避免运行时解析。

  • 仅支持C ++ 03

编辑的代码示例

1 个答案:

答案 0 :(得分:0)

  

所有实例都由库创建为全局变量,并且不可堆叠。

你的意思是这样的,对吧?

static HWManager<DrierPolicy> drierManager;

static HWManager<FridgePolicy> fridgeManager;

然后,让用户了解他们并允许她/他直接使用这些内容有什么不对:

drierManager.doStuff();

fridgeManager.doStuff();

然后......

  

因为我正在连接HW,所以我的HWManagers的不同策略的每个实例都是唯一的

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

(这些是问题,而不是批评。是的,我知道,这不是一个答案 - 它可能是一个 - 但我需要额外的格式,评论不提供)