Удаление неиспользуемых статических элементов экземпляра шаблона - PullRequest
9 голосов
/ 17 января 2012

В настоящее время я занимаюсь разработкой встроенного C ++ на платформе STM32. Наша команда оценивает использование шаблонов для параметризации драйверов для различных аппаратных устройств низкого уровня.

Все действительные специализации шаблонов известны заранее, поэтому мы можем явно указать все допустимые специализации внутри файла реализации (реализация и объявление разделены). Фактически, для нас явная специализация весьма полезна, поскольку она помогает документировать жизнеспособные наборы параметров.

// 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 Ответ

2 голосов
/ 18 января 2012

Ответ (из Edit # 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> также удаляются из конечного исполняемого файла (какфайл карты предлагает).

...