Как boost:: variant и boost:: любая работа?

Как вариант и любой из библиотеки boost работают внутри? В проекте, над которым я работаю, в настоящее время я использую тегированный союз. Я хочу использовать что-то еще, потому что объединения на С++ не позволяют использовать объекты с конструкторами, деструкторами или перегруженными операторами присваивания.

Я запросил размер любого и варианта, и сделал некоторые эксперименты с ними. В моей платформе вариант принимает размер своего самого длинного типа плюс 8 байтов: я думаю, что это всего лишь 8 байт данных типа, а остальное - сохраненное значение. С другой стороны, каждый из них занимает всего 8 байтов. Так как я на 64-битной платформе, я предполагаю, что любой из них содержит указатель.

Как любой знает, какой тип он держит? Как Вариант достигает того, что он делает с помощью шаблонов? Я хотел бы узнать больше об этих классах перед их использованием.

Ответ 1

Если вы читаете boost:: any documentation, они предоставляют источник идеи: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf

Это скрытие основной информации, необходимый навык С++. Изучите это!

Так как наивысший проголосовавший ответ здесь абсолютно неверен, и у меня есть сомнения, что люди действительно пойдут посмотреть на источник, чтобы проверить этот факт, вот базовая реализация любого подобного интерфейса, который будет обертывать любой тип с помощью f ( ) и разрешить его называть:

struct f_any
{
   f_any() : ptr() {}
   ~f_any() { delete ptr; }
   bool valid() const { return ptr != 0; }
   void f() { assert(ptr); ptr->f(); }

   struct placeholder
   {
     virtual ~placeholder() {}
     virtual void f() const = 0;
   };

   template < typename T >
   struct impl : placeholder
   {
     impl(T const& t) : val(t) {}
     void f() const { val.f(); }
     T val;
    };
   // ptr can now point to the entire family of 
   // struct types generated from impl<T>
   placeholder * ptr;

   template < typename T >
   f_any(T const& t) : ptr(new impl<T>(t)) {}

  // assignment, etc...
};

boost:: любая делает ту же основную вещь, за исключением того, что f() фактически возвращает typeinfo const& и предоставляет другой доступ к информации для функции any_cast для работы.

Ответ 2

Ключевое различие между boost::any и boost::variant заключается в том, что any может хранить любой тип, а variant может хранить только один из множества перечисленных типов. Тип any хранит указатель void* для объекта, а также объект typeinfo для запоминания базового типа и обеспечения определенной степени безопасности типов. В boost::variant он вычисляет объект максимального размера и использует "размещение нового" для выделения объекта в этом буфере. Он также сохраняет тип или индекс типа.

Обратите внимание, что если у вас установлен Boost, вы сможете увидеть исходные файлы в "any.hpp" и "variant.hpp". Просто найдите "include/boost/variant.hpp" и "include/boost/any.hpp" в "/usr", "/usr/local" и "/opt/local", пока не найдете установленные заголовки, и вы можете взглянуть.

Изменить
Как было указано в комментариях ниже, в моем описании boost:: any была небольшая неточность. Хотя он может быть реализован с помощью void* (и шаблона уничтожить обратный вызов для правильного удаления указателя), фактическая реализация использует any<T>::placeholder*, с any<T>::holder<T> как подклассы any<T>::placeholder для объединения типа.

Ответ 3

boost::any просто моментальные снимки typeinfo, когда запущен шаблонный конструктор: он имеет указатель на не templated базовый класс, который предоставляет доступ к typeinfo, а конструктор выводит класс типа, удовлетворяющий этому интерфейсу. Такая же методика может быть использована для захвата других общих возможностей набора типов (например, потоковой передачи, общих операторов, определенных функций), хотя boost не обеспечивает контроль над этим.

boost:: variant концептуально похож на то, что вы делали раньше, но не буквально используете union и вместо этого применяете ручной подход к созданию/уничтожению объектов в своем буфере (при явной обработке проблем с выравниванием) он работает вокруг ограничений, которые С++ имеет сложные типы в реальных union s.