2014-10-13 3 views
5

Хорошо, это сложный вопрос.Выполнить код один раз для каждого экземпляра шаблона класса C++

У меня есть шаблон класса C++, который используется несколько раз. Для каждого из этих экземпляров мне нужно выполнить функцию, которая регистрирует некоторые операторы. Это нужно сделать только один раз для экземпляра шаблона до того, как будет использован первый объект этого экземпляра шаблона (что не означает, что он должен быть выполнен при instanciation, который происходит во время компиляции).

До настоящего времени я сделал это вручную. Но это боль. Поэтому я хотел бы выполнить функцию регистрации автоматически.

Моей идеей является вызов защищенного метода регистрации в конструкторе. Однако при каждом экземпляре класса он требует (малых) накладных расходов. Поскольку это делается очень часто, я бы хотел избежать этого.

Я также пытался использовать статический элемент-помощник RAII, но статические члены класса шаблонов не были сконструированы, если они не были активно доступны, поэтому эта попытка не удалась.

Есть ли способ выполнить код при инициализации шаблона класса (с помощью функции или, может быть, с помощью вспомогательного класса RAII) без накладных расходов во время выполнения?

+0

Обычно шаблоны инстанцированный во время компиляции не во время выполнения. Вы уверены, что ваша проблема реальна? – BitTickler

+0

Да, это так. Мне не нужно выполнять код * при * instanciation. Мне нужно выполнить его перед первым использованием объекта. – Silicomancer

ответ

6

Вы можете добавить элемент статических данных, который будет выполнять все, что необходимо в его конструкторе и деструкторе. Вы можете безопасно поместить свое определение в заголовочный файл, поскольку, пока он является шаблоном, он будет определен только один раз. Единственный улов в том, что для его создания у вас должно быть odr-use.

template <typename T> 
class Data { 
public: 
    Data() { 
     std::cout << "creating Data<" << typeid(T).name() << '>' << std::endl; 
    } 
    ~Data() { 
     std::cout << "destroying Data<" << typeid(T).name() << '>' << std::endl; 
    } 
}; 

template<typename T> 
class A { 
    static Data<T> data; 
public: 
    A() { 
     // this is necessary for data to be instantiated 
     (void)data; 
    } 
}; 

// This also should be in a header 
template<typename T> 
Data<T> A<T>::data; 

int main(){ 
    A<int> aInt; 
    A<int> aInt2; 
    A<float> aFloat; 
} 

Demo

EDIT: Это на самом деле немного небезопасно, потому что порядок создания статических объектов в разных единицах трансляции, не определен, поэтому, например, не может быть никакого std::cout в момент exetucion из Data::Data() (поэтому не используйте там какие-либо статические глобальные объекты). Более безопасный подход заключается в вызове статической функции в A::A(), хотя он вводит некоторые накладные расходы:

template<typename T> 
class A { 
    static void createData() { 
     static Data<T> data; 
    } 
public: 
    A() { 
     createData(); 
    } 
}; 
+0

Отлично! Это решение работает для меня! На самом деле я пробовал что-то очень * похожее, но это не сработало, потому что я забыл «шаблон Данные A :: данные; линия. Должен ли я получить какую-то ошибку, забыв добавить эту строку? – Silicomancer

+0

Ах, еще один ... почему "(void) данные;" вместо «данных»? – Silicomancer

+1

@Silicomancer просто 'data;' дает предупреждение о компиляторе 'не имеет никакого эффекта ". –

Смежные вопросы