type erasure(一)

从前面问题我们体会到某些情况下我们需要 type erasure,但是它到底在 C++ 里面意味着什么,又有一些什么样的应用,我们了解的并不多。事实上,这方面的研究还不少。

很多人都提到了 Dave Abrahams 和 Aleksey Gurtovoy 在他们 C++ Template Metaprogramming 一书中的定义

the process of turning a wide variety of types with a common interface into one type with that same interface.

这个抽象的概念有几个具体的例子,std::function 和 boost.any 是最常被用来作为例子的,前者可以隐藏究竟是函数指针、成员函数、functor 还是别的什么,后者可以将任意类型的值存放进去,同时还可以取出来(需要指定类型)。历史上 boost.any 的作者也意识到这个技术可以用来实现 any function/iterator 等等。我们这里根据阅读的一些资料整理一下。

在 C 的年代一种普遍的“type erasure”策略是 void*,比如作为通用排序算法,处理不同类型数据的排序使用的做法就是将所有的类型都转换到 void*,然后通过实现它上面的函数指针获得比较函数。C++ 与其相比,通过 functor 传递比较方法,可以在 STL 上实现 type safe 的排序,不仅仅只是语法上更加漂亮,编译器根据类型可以 inline 这些比较算法(而对于函数指针来说,它是一个运行时的概念,编译器无法 inline)从而获得更高的执行效率。

在 OO 的策略里,Java 系的典型 type erasure 做法是通过公共祖先 Object,就算没有了 type,你永远可以用 Object 来表示那个对象,所有的 Java generics 只是在编译时检查 type,运行时全部是 Object,这允许我们做很多邪恶的事情。这样一来同样的排序我们可以接受 Object,通过某些 Interface 来做实际的比较,但是这样一来传递的对象如果不符合要求,就必须在运行时处理这些问题。事实上如此一来会产生一些更加奇怪的结果,最简单的整数排序必须引入 interface,这意味着需要 virtual function call…

事实上,我们这里的问题是一个非常根本性的 programming 问题,面对一个问题(排序),我们需要的一个一般性的算法需要对所有能够操纵类型的对象有一个 interface(比较函数),使用 template 是一种 duck-typing 的做法(后果嘛… 反模板的同学尽情说吧),所谓的 type erasure 技巧在这里就是提供某种类型(如 std::function<bool (const T&, const T&)>),它能够将符合条件的类型(functor、function pointer etc)自动的转换成为它自身,这样处理这个问题的时候可以使用这个类型的接口(operator())。这样的好处在于此时接口将不再与任意一个具体的 type 发生关系,不再需要 template(这也意味着更加容易写成 virtual?从而有 mock 的机会?)

又比如说如果我们需要处理一些 iterator 的逻辑,我们有各种容器类提供不同类型的 iterator,然而我们有时候并不关心具体是什么 iterator 但是我们希望在 interface 上有机会避免 template,这时我们同样需要一个 type erasure 的东西。这可以参考 Thomas Becker 的文章,他分析了 boost.any 的结构实现了 any iterator。同样 boost.any 要解决的也就是一个简单的存放在容器里面类型不同时的 type erasure。我们也很容易看到,每个 type erasure 对应某些对应问题的 interface

  • std::function 解决的是 operator()
  • boost.any 解决的是 dereference back
  • any_iterator 解决的是 operator++ 和 operator*

本文参考这里

——————
And it came to pass, as she spake to Joseph day by day, that he hearkened not unto her, to lie by her, or to be with her

Advertisements
type erasure(一)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s