Удаление неиспользуемых статических элементов экземпляра шаблона

В настоящее время я занимаюсь разработкой встроенного C++ на платформе am 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, из явно созданных, но неиспользуемых шаблонов?

С уважением, Арне

Изменить № 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


person Arne    schedule 17.01.2012    source источник
comment
Если вы нашли решение своей проблемы, вы должны опубликовать его как ответ.   -  person Georg Fritzsche    schedule 17.01.2012
comment
Звучит как странный тик компилятора, так как на самом деле не должно быть никакой разницы, имхо.   -  person Xeo    schedule 17.01.2012
comment
что это за хромой компилятор и какая версия?   -  person BЈовић    schedule 17.01.2012
comment
@VJovic: это текущий источник кода arm-none-eabi-gcc. Я уже не на работе, поэтому не могу проверить точную версию.   -  person Arne    schedule 17.01.2012
comment
@Xeo: я ожидаю, что это тоже не будет иметь никакого значения. Может быть, компилятор не может исключить побочные эффекты конструктора и поэтому оставляет его (и статические переменные)?   -  person Arne    schedule 18.01.2012


Ответы (1)


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

person Arne    schedule 18.01.2012