boost库中的变体和任何内部工作原理如何?在我正在进行的项目中,我目前使用标记的联合。我想使用其他东西,因为C ++中的联合不允许你使用带有构造函数,析构函数或重载赋值运算符的对象。
我查询了任何和变体的大小,并用它们做了一些实验。在我的平台中,variant采用其最长可能类型的大小加上8个字节:我认为我只是8字节的类型信息,其余的是存储值。另一方面,任何只需要8个字节。由于我在64位平台上,我猜任何只是一个指针。
怎么知道它有什么类型? Variant如何通过模板实现它的功能?在使用它们之前,我想更多地了解这些类。
答案 0 :(得分:78)
如果你阅读了boost :: any文档,他们提供了这个想法的来源:http://www.two-sdg.demon.co.uk/curbralan/papers/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函数才能工作。
答案 1 :(得分:20)
boost::any
和boost::variant
之间的主要区别在于any
可以存储任何类型,而variant
只能存储一组枚举类型中的一种。 any
类型存储指向对象的void*
指针,以及用于记住基础类型的typeinfo
对象,并强制执行某种程度的类型安全性。在boost::variant
中,它计算最大大小的对象,并使用“placement new”在此缓冲区中分配对象。它还存储类型或类型索引。
请注意,如果安装了Boost,您应该能够在“any.hpp”和“variant.hpp”中看到源文件。只需在“/ usr”,“/ usr / local”和“/ opt / local”中搜索“include / boost / variant.hpp”和“include / boost / any.hpp”,直到找到已安装的标题,然后你可以看看。
修改的
正如下面的评论中指出的那样,我对boost :: any的描述略有不准确。虽然可以使用void*
(以及模板化的销毁回调来正确删除指针)来实现,但实际实现使用any<T>::placeholder*
,any<T>::holder<T>
作为any<T>::placeholder
的子类来统一类型。
答案 2 :(得分:9)
boost::any
只是在模板化构造函数运行时对typeinfo
进行快照:它有一个指向非模板化基类的指针,该基类提供对typeinfo的访问,构造函数派生一个特定于类型的类满足那个界面。实际上可以使用相同的技术来捕获一组类型的其他常见功能(例如,流式传输,公共运算符,特定功能),尽管boost不提供对此的控制。
boost :: variant在概念上类似于你之前所做的,但不是字面上使用union
而是采用手动方法在缓冲区中放置构造/销毁对象(同时处理对齐问题)明确地说,它解决了C ++在实际union
s中复杂类型的限制。