67

boost 库中的变体和任何内容如何在内部工作?在我正在进行的一个项目中,我目前使用标记的联合。我想使用其他东西,因为 C++ 中的联合不允许您使用带有构造函数、析构函数或重载赋值运算符的对象。

我查询了任何和变体的大小,并用它们做了一些实验。在我的平台中,variant 取其最长可能类型的大小加上 8 个字节:我认为它只是 8 个字节的类型信息,其余的是存储的值。另一方面,any 只需要 8 个字节。由于我在 64 位平台上,我猜任何人都只是持有一个指针。

Any 怎么知道它持有什么类型?Variant 如何通过模板实现它的功能?在使用它们之前,我想更多地了解这些类。

4

3 回答 3

82

如果您阅读 boost::any 文档,它们会提供该想法的来源:http: //www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf

这是基本的信息隐藏,是必备的 C++ 技能。学习吧!

由于这里投票得最高的答案是完全不正确的,而且我怀疑人们是否真的会去查看源代码来验证这一事实,这里有一个 any like 接口的基本实现,它将用 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 函数工作的其他信息访问。

于 2011-02-14T05:35:28.077 回答
19

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*, withany<T>::holder<T>作为any<T>::placeholder统一类型的子类。

于 2011-02-14T05:00:11.633 回答
8

boost::any只是在模板化构造函数运行时的快照typeinfo:它有一个指向非模板化基类的指针,该基类提供对 typeinfo 的访问,并且构造函数派生了一个满足该接口的特定于类型的类。相同的技术实际上可以用于捕获一组类型的其他通用功能(例如流、通用运算符、特定函数),尽管 boost 不提供对此的控制。

boost::variant 在概念上与您之前所做的类似,但不是从字面上使用 aunion而是采用手动方法在其缓冲区中放置构造/销毁对象(同时显式处理对齐问题)它可以解决以下限制: C++ 在实际unions 中有 re 复杂类型。

于 2011-02-14T05:13:21.847 回答