![]() |
Variant или any | ||
«Variant» это такой объект-контейнер, в который можно поместить любой другой объект любого типа, а сами «варианты» можно сложить в массив, поскольку с точки зрения языка они явлются одним и тем же типом, независимо от того, что внутри них хранится. Помните наш мультфильм про Винни-пуха? «В нем можно держать все что угодно» — говорил Винни-пух про горшочек из-под меда. Аналогично, рассматриваемый паттерн позволяет в одном и том же объекте хранить значения любого типа. «Variant» это горшочек, в котором можно держать все что угодно. | ||
|
Рассмотрим одну из возможных реализаций паттерна «Variant». Данный паттерн можно реализовать большим количеством способов. Я придумал такой (хотя, с точки зрения буста, это все же any :-) |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include <memory> #include <string> class variant { public: template <class T> variant& operator = (T const& t) { typedef type<T> assign_type; object = std::auto_ptr<assign_type>(new assign_type(t)); return *this; } template <class T> operator T () { typedef type<T> assign_type; assign_type& type = dynamic_cast<assign_type&>(*object); return type.get(); } private: class base { public: virtual ~base() {} }; typedef std::auto_ptr<base> base_ptr; template <class T> class type : public base { public: type(T const& t) : object(t) { } T get() const { return object; } private: T object; }; base_ptr object; }; struct dummy { int a; int b; int c; }; int main() { variant v1, v2, v3, v4; v1 = 2; v2 = 5.0f; v3 = std::string("Pot of gold"); v4 = dummy(); int i = v1; float f = v2; std::string s = v3; dummy d = v4; return 0; } |
Пример довольно простой, но при этом он хорошо иллюстрирует все достоинства и недостатки данного паттерна. | ![]() Пустой горшочек — тоже variant! | |
Цель паттерна — предоставить возможность осуществлять единообразную работу с разнотипными данными. Например, эти разнотипные данные можно хранить в одном контейнере. | ||
Основной недостаток — перенос контроля типов с compile-time-а на run-time. | ||
Существуют ситуации, в которых данный паттерн может дать сиюминутное удобство. Однако, чаще всего за такое удобство впоследствии придется заплатить, так как воспользовавшись паттерном «Variant», пользователь освобождает компилятор от контроля типов и перетаскивает эту функцию на собственные плечи. Поэтому, если вдруг вы испытали потребность в этом паттерне, прежде всего задумайтесь, почему это произошло. Скорее всего найдется более безопасное и не менее изящное решение. | ||
boost::any и boost::variant имеют более навороченную функциональность и, кроме того, более безопасны, чем мой вариант. Однако, и они не решают основную проблему — отсутствие возможности выполнить полноценную проверку типов на этапе компиляции. |
|
Статистика |
|