前段时间在 csdn 上发了帖子讨论过这个问题,当时讨论了有些地方还是不懂。今天又看了下源码,写下来备忘:(研究 MSVC 的部分)
先看 BOOST_TYPEOF 的主要计算流程:
1 2 | # define BOOST_TYPEOF(expr) \
boost::type_of::msvc_typeid_wrapper< typeid (boost::type_of::encode_start(expr)) >::type
|
这里主要有三个步骤:
1. encode_start( expr )。这一步会将 expr 的类型注册, 会形成一个签名的模板类: msvc_typeid_wrapper <typeid(expr)> 类, expr 的 type 就存储在这个类中。
2. typeid ( $(1) )。 这一步将第一步计算出的 type 结果(注意,这个结果是函数 encode_start() 返回的,不能直接拿来作类型用)再做 typeid 计算, 生成一个 type_info 对象
3. msvc_typeid_wrapper< $(3) >。这一步会通过第二部计算出的 type_info 对象来找到注册的对应的 type。完毕。
encode_start
这是个无实作的模板函数,主要完成下列功能:
1. 如果参数的类型没有注册,注册之
2. 返回这个注册的类型
函数的源码:
1 2 3 4 5 6 7 | template < typename T> typename disable_if<
typename is_function<T>::type,
typename encode_type<T>::input_type>::type encode_start(T const &);
template < typename T> typename enable_if<
typename is_function<T>::type,
typename encode_type<T>::input_type>::type encode_start(T&);
|
暂且不管 is_function.
这个函数主要通过模板类 encode_type 来完成具体功能(两步都有具体的对应语句):
1 2 3 4 5 6 7 8 9 10 11 | template < typename T>
struct encode_type
{
typedef encode_type<T> input_type;
typedef typename msvc_register_type<input_type,msvc_typeid_wrapper< typeid (input_type)> >::id2type registered_type;
typedef T type;
};
|
类型注册是通过模板类 msvc_register_type 来完成注册,有两个参数,一个是 encode_type 要注册的类型, 注册成另一个参数 msvc_typeid_wrapper, 这样会形成一个 签名为 typeid(encode_type) 的 msvc_typeid_wrapper 签名模板类( 这个模板类中存储有 type )。
至此,形成了一个模板类签名,注册成功了。这里我们知道了 以后就是通过 msvc_typeid_wrapper 类来找到 typeid(expr ) 对应的 type的。
具体注册过程,就更简单了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | template < typename ID>
struct msvc_extract_type
{
struct id2type;
};
template < typename T, typename ID>
struct msvc_register_type : msvc_extract_type<ID>
{
typedef msvc_extract_type<ID> base_type;
struct base_type::id2type
{
typedef T type;
};
};
|
看,就是通过模板的特化来实现的,这是模板的最普遍、最常用的技法。
msvc_typeid_wrapper
msvc_typeid_wrapper< typeid(...) >
这个类现在可以看成一个映射集合了,通过 typeid 能找到对应的注册的 type。之所以可以看成映射集合,主要还是 模板的特化起的效果,因为在找类型type之前就完成了模板的特化动作,注册完毕。
msvc_typeid_wrapper 的模板类很简单:
1 2 3 4 5 6 7 8 9 10 | template < const std::type_info& ref_type_info>
struct msvc_typeid_wrapper {
typedef typename msvc_extract_type<msvc_typeid_wrapper>::id2type id2type;
typedef typename id2type::type wrapped_type;
typedef typename wrapped_type::type type;
};
|
模板类的参数是 type_info , 这个 type_info 可以作为编译器量参与计算,这点很关键。
typeid
typeid也和 sizeof一样在编译期完成计算, 返回 一个 type_info 对象, 这个对象是唯一的。
我以前不知道的是这个 typeid 返回的对象可以作为模板类的参数,牢记。