Как повысить :: вариант и повысить :: любой работы? - PullRequest
65 голосов
/ 14 февраля 2011

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

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

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

Ответы [ 3 ]

78 голосов
/ 14 февраля 2011

Если вы читаете повышение :: любую документацию, они предоставляют источник идеи: http://www.two -sdg.demon.co.uk / curbralan /apers / ValuedConversions.pdf

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

Поскольку ответ с наибольшим количеством голосов здесь абсолютно неверен, и я сомневаюсь, что люди действительно пойдут посмотреть на источник, чтобы проверить этот факт, вот базовая реализация любого подобного интерфейса, который обернет любой тип с помощью 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 :: any делает то же самое, за исключением того, что f () фактически возвращает typeinfo const& и предоставляет доступ к другой информации для работы функции any_cast.

20 голосов
/ 14 февраля 2011

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

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

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

9 голосов
/ 14 февраля 2011

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

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

...