关于type erasure
哇,好久没有写blog了,再不写的话,blog的秘密都要忘记了,嘿嘿。
最近在试着参与一个开源项目,名字叫avim(A Vibrate IM),别想多了哟。地址是:https://github.com/avplayer/avim.git 我在看它的代码的是有一个地方一直不太明白,大概就是这个页面上面的代码 https://github.com/avplayer/avim/blob/master/libavproto/include/avif.hpp,关于这个avif 类的定义和 avtcpif 之间的关系上面,我一直很模糊,后来问了代码的主人,他给我了一个说法,说它是一个 “type erasure” 的用法。之间对它还未有所闻,于是今天我关注了下它的巧妙用法。
那么什么叫type erasure呢?WiKi上面对它的定义如下
In programming languages, type erasure refers to the compile-time process by which explicit type annotations are removed from a program, before it is executed at run-time. Operational semantics that do not require programs to be accompanied by types are called type-erasure semantics, to be contrasted with type-passing semantics. The possibility of giving type-erasure semantics is a kind of abstraction principle, ensuring that the run-time execution of a program does not depend on type information. The opposite of type erasure is called reification.
大致的意思就是说,type erasure 其实是一种抽象,它忽略了具体的类型,不必对具体类型进行检查。这个功能对于强类型语言来说,比如C++, 就是一种解放。因为在C++中我们会由于类型不匹配而遇到大堆的编译错误,当然这并不是type erasure主要解决的问题。
在说到type erasure的定义的时候,一些人会想到模板,对,模板也算是一种类型弱化吧,假如,我们需要一个功能,且它需要是弱类型的(即忽略类型),那么我们会想到什么呢? 模板,虚函数,yeah.
比如要实现一个function,那么模板的写法会是:
template <typename T>
void function(T arg1)
{
return arg1.function();
}
虚函数的做法:
class base
{
virtual void function() = 0;
}
class derived : public base
{
virtual void function()
{
......
}
};
void function(base* ptr)
{
return ptr->function();
}
这两种方法,都实现了弱类型的特点,但它们有各自的缺点,比如模板的方法,你要是有100个类型的话,系统会根据相应类型在编译期间生成100个不同版本的function,浪费了大量的编译时间;虚函数的方法,也不那么招人喜欢,因为如果想要使用function这个接口,你的类型必须继承自class base; 这是当年MFC的传统做法,如果你想使用某个功能,你要继承某个类,有一种被强奸的感觉。老一代的程序员们都已经习惯了这种做法,并且很多人还沉浸在继承带来的优越感之中,但他们也被继承引来了不少的不便,这里就不细谈了。
这个时候用过boost的同学,他们可能会想到boost里面的boost::any, 或者boost::function, 当然 boost::function这个东西已经加入到C++标准里面了。std::function可以存储什么呢?
它可以存储函数指针,lambda表达式,函数对象 等。对于强类型语言C++来说,这是很不可思议的事情。而boost::any呢,它可以存储任意的类型,卧槽,神马?任意类型,对,你没看错,是任意类型。那么你想到什么没有,之前我有一个需求,需要做一个可接受任意参数的接口,我第一时间想到了C语言里类似跟printf实现原理一样东西,可我嫌那样太不美观,我就使用了boost::any,加一个vector来存储变量,这样很简单的实现了接受任意参数的接口。那么你有没有想过boost::any和boost::function,为什么能够做到这样的弱类型?其实很简单,具体的话你参考下boost::any的源码,当然也可以参考我自己写的一份简单的原理性代码,
地址:https://github.com/xiaopeifeng/CodeTricks/blob/master/type_erasure.cc
如果硬要写一份模板代码的话,那么我想应该是这个样子的:
class Base {
public:
virtual ~Base();
virtual some_common_func() = 0 ;
} ; template < class T >
class adapter : public Base
{
T t;
public:
some_common_func()
{
t.some_common_func();
}
adapter(T _t): t(_t){}
}; class interface
{
Base * ptr;
public:
template<class T>
interface(T t)
{
ptr = new adapter<T>(t);
}
some_common_func()
{
ptr->some_common_func();
}
};
这个class interface才是你需要的具体的类型,你就完全可以在后面的代码里使用interface去作为接口参数,而具体的实现则可以自己再定义另外的类,而这个类不必去继承自interface(但是它却有一个is a 的语义), 只需要去实现some_common_func的功能就行了,这样子就对接受interface为参数的接口,就有了type erasure的特性了,因为它不会再去检查具体的参数类型了,只要改参数实现了需要调用的方法就OK了。
参考:https://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i/
关于type erasure的更多相关文章
- Java魔法堂:解读基于Type Erasure的泛型
一.前言 还记得JDK1.4时遍历列表的辛酸吗?我可是记忆犹新啊,那时因项目需求我从C#转身到Java的怀抱,然后因JDK1.4少了泛型这样语法糖(还有自动装箱.拆箱),让我受尽苦头啊,不过也反映自己 ...
- Breaking Down Type Erasure in Swift
Type Erasure Pattern We can use the type erasure pattern to combine both generic type parameters and ...
- A “Type Erasure” Pattern that Works in Swift:类型域的转换
新视角:通过函数式编程的范畴理论来看待这个问题会更容易理解: 在低层类型无法很好表达的类型,可以将其转化为高阶类型进行表示. 将协议的实现类型转化为monad类型: 解决将具有关联类型的协议当作类型的 ...
- Type Erasure with Pokemon---swift的类型擦除
我感觉这个是swift的设计缺陷. 类型擦除:解决泛型类型作为公用类型的问题 是抽象的公用机制的一种实现方式. 1)类型擦除并不能解决类型不一致的兼容问题,只能解决类似继承一致性的兼容问题. 2)擦除 ...
- 关于语法节点Tree、类型Type和符号Symbol
每个语法节点Tree都有Type属性,部分的语法节点有Symbol属性,如下: 与Symbol类型与Type类型之间的关系如下: 下面是Symbol与Type之间的关系: (1)MethodSymbo ...
- 类型检查和鸭子类型 Duck typing in computer programming is an application of the duck test 鸭子测试 鸭子类型 指示编译器将类的类型检查安排在运行时而不是编译时 type checking can be specified to occur at run time rather than compile time.
Go所提供的面向对象功能十分简洁,但却兼具了类型检查和鸭子类型两者的有点,这是何等优秀的设计啊! Duck typing in computer programming is an applicati ...
- 转职成为TypeScript程序员的参考手册
写在前面 作者并没有任何可以作为背书的履历来证明自己写作这份手册的分量. 其内容大都来自于TypeScript官方资料或者搜索引擎获得,期间掺杂少量作者的私见,并会标明. 大部分内容来自于http:/ ...
- Scala Reflection - Mirrors,ClassTag,TypeTag and WeakTypeTag
反射reflection是程序对自身的检查.验证甚至代码修改功能.反射可以通过它的Reify功能来实时自动构建生成静态的Scala实例如:类(class).方法(method).表达式(express ...
- 18.Java泛型
1.为什么需要泛型 List list1=new ArrayList(Arrays.asList(new String("string"),new Integer(20))); S ...
随机推荐
- 【转】AWK 简明教程
本文转自:http://coolshell.cn/articles/9070.html 有一些网友看了前两天的<Linux下应该知道的技巧>希望我能教教他们用awk和sed,所以,出现了这 ...
- ACM-ICPC退役选手的发言——满满的正能量(短视频)
这是我在北京林业大学ACM-ICPC竞赛说明会上发言的录像 希望能激励大家在奋斗的道路上披荆斩棘,勇往直前!
- node01-创建服务器
node学习笔记目录:node01-创建服务器 node02-util node03-events node04-buffer node05-fs node06-path node07-http no ...
- Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds -----》myeclipse2015
错误:Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds 错误提示就是我们限定了部署的时间导致的错 ...
- java学习第一天 回顾以前
1.1常量: 基本数据类型常量 字符常量 整数常量的表现形式:一进制的形式来表示(二进制,八进制,十进制,十六进制) 生活中:十进制(0-9) ,星期(七进制(0-6)) ,时间(十二进制(0-11 ...
- 编辑 Ext 表格(一)——— 动态添加删除行列
一.动态增删行 在 ext 表格中,动态添加行主要和表格绑定的 store 有关, 通过对 store 数据集进行添加或删除,就能实现表格行的动态添加删除. (1) 动态添加表格的行 gridS ...
- 安装学习nginx记录
通过查看nginx目录下的log文件,发现80端口没有权限使用 查找文章发现: netstat -aon|findstr ":80" 有的进程ID占用多了80端口,看监听的端口 启 ...
- cryptkeeper的使用
转自:http://www.linuxidc.com/Linux/2011-06/37070.htm Cryptkeeper 是加密文件系统 EncFS 的前端工具,以 Gnome Applet 方式 ...
- scala中的面向对象定义类,构造函数,继承
我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面 ...
- Linux下的tmpfs文件系统(/dev/shm)
转自:http://www.2cto.com/os/201411/354888.html 介绍 /dev/shm/是一个使用就是tmpfs文件系统的设备,其实就是一个特殊的文件系统.redhat中默认 ...