我目前参与的STM32上午嵌入式平台的C++开发。我们的团队正在评估使用模板来为各种低级硬件设备的驱动程序进行参数化。删除不使用的模板实例化的静态成员
所有有效模板专门在事先知道这样,我们可以给所有有效的专业化明确内实现文件(执行和声明分开)。事实上,对我们而言,明确的专门化非常有用,因为它有助于记录可行的参数集。
// file i2c_dev.h
template<typename traits>
struct i2c_dev
{
public:
static void init();
static void send();
static bool busy();
...
private:
static i2c_transfer periodic_transfer; // class with used-defined constructor
};
// traits class for configuration A
struct i2c_dev_traitsA
{
enum
{
I2Cx_BASE = I2C1_BASE
, PORTx_BASE = GPIOB_BASE
, PORTx_PIN_TX = PB08
, PORTx_PIN_RX = PB09
};
};
// traits class for configuration B, different I2C peripherial and pinout
struct i2c_dev_traitsB
{
enum
{
I2Cx_BASE = I2C2_BASE
, PORTx_BASE = GPIOA_BASE
, PORTx_PIN_TX = PA01
, PORTx_PIN_RX = PA02
};
};
// file i2c_dev.cpp
// Implementation of template functions
template<typename traits>
void i2c_devy<traits>::init() { ... }
...
// explcitly specialize for all valid traits classes
template class i2c_dev<i2c_dev_traitsA>;
template class i2c_dev<i2c_dev_traitsB>;
虽然一般只将实际使用的特例之一,未使用的专业化生成的代码被链接器,这正是我们想要的东西从最终图像去除。
但是,每个模板专业化的静态成员变量 - periodic_transfer
保留在可执行文件中,如arm-none-eabi-nm
工具生成的存储器映射中所示。这可能是由于i2c_transfer
不是POD,但具有用户定义的构造函数。当构造函数被删除时,把它变成POD类型,静态成员也会消失。
有没有办法去除的显式实例化静态非POD成员,但未被使用的模板?
问候, 阿恩
编辑#1:重新思考这个问题后,我想出了以下解决方案,这显然解决了这个问题。
当类i2c_transfer
这实际上有它的构造仅仅是为了清楚和易用性,有它的数据成员搬进了POD基类i2c_transfer_pod
这样的:
struct i2c_transfer_pod
{
protected:
uint16_t m_size;
char* m_buffer;
};
struct i2c_transfer : public i2c_transfer_pod
{
public:
i2c_transfer();
i2c_transfer(i2c_direction_enum dir, char*buffer, uint16_t count);
bool failed();
bool succeeded();
};
然后,未使用的i2c_dev<traits>
的静态成员专业化也从最终的可执行文件中移除(如地图文件所示)。
编辑#2:虽然回答一个自我感觉有点跛。我谨请上提出的解决方案的意见。有没有更优雅的方式?编译器是否真的(正如我所想的那样)优化了额外的派生?
编辑#3:我关闭问题,因为该解决方案为我工作。如果能够更深入地了解观察到的行为的原因,那将是很好的。
有问题的编译器是arm-none-eabi-gcc (Sourcery G++ Lite 2011.03-42) 4.5.2
如果你找到了解决你的问题,你应该张贴它作为一个答案。 – 2012-01-17 19:04:42
听起来像一个奇怪的编译器嘀嗒,因为根本不应该有任何区别,恕我直言。 – Xeo 2012-01-17 19:15:07
什么版本是什么版本? – 2012-01-17 19:55:25