boost::variant 和 boost::any 如何工作?

发布于 2024-10-17 09:28:07 字数 325 浏览 7 评论 0原文

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

我查询了any和variant的大小,并用它们做了一些实验。在我的平台中,variant 采用其最长可能类型的大小加上 8 个字节:我认为它只是 8 个字节的类型信息,其余的是存储的值。另一方面,any 只占用 8 个字节。因为我在 64 位平台上,所以我猜 any 只是保存一个指针。

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

How do variant and any from the boost library work internally? In a project I am working on, I currently use a tagged union. I want to use something else, because unions in C++ don't let you use objects with constructors, destructors or overloaded assignment operators.

I queried the size of any and variant, and did some experiments with them. In my platform, variant takes the size of its longest possible type plus 8 bytes: I think it my just be 8 bytes o type information and the rest being the stored value. On the other hand, any just takes 8 bytes. Since i'm on a 64-bit platform, I guess any just holds a pointer.

How does Any know what type it holds? How does Variant achieve what it does through templates? I would like to know more about these classes before using them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

怪我入戏太深 2024-10-24 09:28:07

如果您阅读 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 函数进行工作的其他信息访问。

If you read the boost::any documentation they provide the source for the idea: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf

It's basic information hiding, an essential C++ skill to have. Learn it!

Since the highest voted answer here is totally incorrect, and I have my doubts that people will actually go look at the source to verify that fact, here's a basic implementation of an any like interface that will wrap any type with an f() function and allow it to be called:

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 does the same basic thing except that f() actually returns typeinfo const& and provides other information access to the any_cast function to work.

陌路黄昏 2024-10-24 09:28:07

boost::anyboost::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::placeholder*,其中 < code>any::holder作为 any::placeholder 的子类,用于统一类型。

The key difference between boost::any and boost::variant is that any can store any type, while variant can store only one of a set of enumerated types. The any type stores a void* pointer to the object, as well as a typeinfo object to remember the underlying type and enforce some degree of type safety. In boost::variant, it computes the maximum sized object, and uses "placement new" to allocate the object within this buffer. It also stores the type or the type index.

Note that if you have Boost installed, you should be able to see the source files in "any.hpp" and "variant.hpp". Just search for "include/boost/variant.hpp" and "include/boost/any.hpp" in "/usr", "/usr/local", and "/opt/local" until you find the installed headers, and you can take a look.

Edit
As has been pointed out in the comments below, there was a slight inaccuracy in my description of boost::any. While it can be implemented using void* (and a templated destroy callback to properly delete the pointer), the actualy implementation uses any<T>::placeholder*, with any<T>::holder<T> as subclasses of any<T>::placeholder for unifying the type.

在巴黎塔顶看东京樱花 2024-10-24 09:28:07

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

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

boost::any just snapshots the typeinfo while the templated constructor runs: it has a pointer to a non-templated base class that provides access to the typeinfo, and the constructor derived a type-specific class satisfying that interface. The same technique can actually be used to capture other common capabilities of a set of types (e.g. streaming, common operators, specific functions), though boost doesn't offer control of this.

boost::variant is conceptually similar to what you've done before, but by not literally using a union and instead taking a manual approach to placement construction/destruction of objects in its buffer (while handling alignment issues explicitly) it works around the restrictions that C++ has re complex types in actual unions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文