Как то раз я встретил реализацию шаблонного класса для хранения объектов разных типов, которая мне не понравилась. Если упростить ситуацию, то этот класс выглядит так:
struct val_base { virtual ~val_base() = 0; template<typename T> bool is_type() const; }; template <typename T> struct val : public val_base { T value_; };
Класс этот общего назначения и поэтому не представляется возможным определить сразу набор виртуальных функции для операций с его потомками. Поэтому используется функции is_type<T> и работа с экземпляром класса выглядит таким образом
val_base * v; ... if(v->is_type<int>()) { int val = static_cast<val<int> *>(v)->value_; ... } else if(v->is_type<double>()) { double val = static_cast<val<double> *>(v)->value_; ... } ...
Реализована функция is_type<T> так:
template<typename T> bool val_base::is_type() const { return dynamic_cast<const val<T>*>(this) != NULL; }
Мне это не понравилось, так как были подозрения что эта реализация имеет серьёзные проблемы с производительностью. Во первых производятся множественные вызовы функции is_type, во-вторых использование dynamic_cast даже в этом простейшем случае может быть довольно накладным. Кроме того есть и другие причины не любить такой метод использования этого класса - довольно сложно сопровождать это решение в случае расширения списка хранимых типов, да и это просто некрасиво. Дальнейший текст посвящен измерению производительности различных методов работы с этим классом. Забегая вперед - метод работы, использующий is_type<T> реализованный с помощью dynamic_cast, действительно самый медленный, более быстрые методы могут работать в 10 раз быстрее.