删除未使用的模板实例化的静态成员
Removal of unused template instantiation's static members
我目前参与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成员?
谨致问候,Arne
编辑#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
答案(来自编辑#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>
专门化的静态成员也会从最终可执行文件中删除(如映射文件所示)。
- 如何正确实例化静态字段 tat 是另一个类对象
- C - 初始化静态成员的方法
- 如何在运行时使用静态成员函数初始化静态成员变量
- 虚幻引擎:实例化静态网格体在实例化时不旋转
- 如何在班级中声明和初始化静态成员
- 向模板化静态成员初始化添加和不添加'typename'都会出错
- 初始化静态成员使编译工作.但是为什么
- 使用作用域内生成的指针初始化静态成员
- 初始化静态成员类(用于信号处理程序)
- 使用宏观使用宏来明确实例化类成员函数
- 可以通过成员初始化列表初始化静态成员变量
- 如何用功能指针作为参数初始化静态成员的模板
- 运行主后,是否可以初始化静态成员变量
- 模板化静态成员函数是如何解析的
- 非实例化模板成员的编译时错误,而不是链接时错误
- 为什么要实例化没有成员的类
- 在C++中初始化静态成员
- 控制C++中的实例化和成员变量
- 必须初始化静态成员
- 初始化静态成员变量值的正确位置