[C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化
[C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化
// point_test.cpp : 知识点练习和测试,用于单步调试,跟踪。
//
#include "stdafx.h"
#include <functional>
#include <string>
#include <iostream>
using namespace std;
//for _1, _2, _3...
using namespace std::placeholders;
template<class T1,class T2> const T1 my_strcat(const T1 &t1,const T2 &t2)
{
return std::move(t1 + t2);
}
/*
测试例子演示了std::bind 和 std:function 的各种组合以及调用的方式
如果你的编译器编译失败,请尽可能的先去掉 const 后编译,如果全部去掉后
还是编译失败,请把你的编译器升级到最高版本或者换了它。
*/
void test_bind()
{
std::string s1 = "aaa",s2 = "BBB",ss = "";
ss = std::bind(my_strcat<std::string,std::string>,s1,s2)();
std::cout<<ss<<endl;
ss = my_strcat<std::string,std::string>(s1,s2);
std::cout<<ss<<endl;
std::function<const std::string (std::string,std::string)> f1 ;
f1 = std::bind(my_strcat<std::string,std::string>,_1,_2);
ss = f1(s1,s2);
std::cout<<ss<<endl;
std::function<std::string ()> f2;
f2 = std::bind(my_strcat<const std::string,std::string>,s1,s2);
ss = f2();
std::cout<<ss<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
test_bind();
system("pause");
return 0;
}
/*输出结果是:
aaaBBB
aaaBBB
aaaBBB
aaaBBB
请按任意键继续. . .
*/
为了比较熟练的看懂各式各样的宏定义,现在先举出一个推导的例子。我们这里以 std::function 的
源代码为例逐步展开,追根溯源,其间各种模版和宏定义令你目不暇接,叹为观止。
0. 总体流程
总体来看,宏定义
_VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
是6个宏定义
_VARIADIC_CALL_OPT_X1,而每个_VARIADIC_CALL_OPT_X1又是3个模板类 _Get_function_impl 的定义
所以6 *3 总计是18个_Get_function_impl的定义
1. std::function 定义
std::function 申明如下
// TEMPLATE CLASS function
template<class _Fty>
class function
: public _Get_function_impl<_Fty>::type
{ // wrapper for callable objects
public:
typedef function<_Fty> _Myt;
typedef typename _Get_function_impl<_Fty>::type _Mybase;
function() _NOEXCEPT
{ // construct empty function wrapper
this->_Reset();
}
......省略部分定义和实现
//上面的的代码就调用了这个赋值函数
template<class _Fx>
_Myt& operator=(_Fx&& _Func)
{ // move function object _Func
this->_Tidy();
this->_Reset(_STD forward<_Fx>(_Func));
return (*this);
}
......省略部分定义和实现
private:
template<class _Fty2>
void operator==(const function<_Fty2>&); // not defined
template<class _Fty2>
void operator!=(const function<_Fty2>&); // not defined
};
我们重点关注申明这句 template<class _Fty> class function : public _Get_function_impl<_Fty>::type,
_Get_function_impl<_Fty>::type 何许人也,能当它的父类?
2. _Get_function_impl<_Fty>
我们继续追踪,有如下定义
template<class _Tx> struct _Get_function_impl;
那不对啊,上面的定义应该不是全部的 _Get_function_impl定义。怀疑何在呢?我们看std::function 类
里面的移动赋值运算符 template<class _Fx> _Myt& operator=(_Fx&& _Func),里面的实现调用了
_Tidy(),this->_Reset(_STD forward<_Fx>(_Func));这些函数std::function 里面都没有实现啊,那只有一种可能,
是父类里面实现了这些函数,但是我们看到_Get_function_impl类并没有任何实现啊。那实现到哪里去了呢?那父
类还有那些诡异的东东呢? 下面熊出没,注意!!!
3. 追踪 _Get_function_impl
我们看到 _Get_function_impl 没有任何实现,下面还有几个名称比较类似宏定义。
#define _CLASS_GET_FUNCTION_IMPL( \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4) \
template<class _Ret COMMA LIST(_CLASS_TYPE)> \
struct _Get_function_impl<_Ret CALL_OPT (LIST(_TYPE))> \
{ /* determine type from argument list */ \
typedef _Func_class<_Ret COMMA LIST(_TYPE)> type; \
};
#define _CLASS_GET_FUNCTION_IMPL_CALLS( \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4) \
_VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, __cdecl, X2, X3, X4)
_VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
我们展开看看,里面有何端倪。
4. 展开 _VARIADIC_EXPAND_0X
我们继续追,在文件 xstddef 里面,我们发现了它的定义。xstddef 是公共的STL 实现的定义,从
文件名称可以明显的看出功能。
// for 0-X args
#define _VARIADIC_EXPAND_0X(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4)
继续展开 _VARIADIC_EXPAND_0 和 _VARIADIC_EXPAND_1X
我们把 _VARIADIC_EXPAND_1X 也全部展开
#define _VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_2X(FUNC, X1, X2, X3, X4)
继续展开_VARIADIC_EXPAND_2X,注意,这里标明了最大支持5个函数参数,这个就是
为什么 std::function 最大支持5个函数参数。
#if _VARIADIC_MAX == 5
#define _VARIADIC_EXPAND_2X _VARIADIC_EXPAND_25
#define _VARIADIC_EXPAND_25(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_3(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_4(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4)
_VARIADIC_EXPAND_0 最终展开就是这个定义了
// call FUNC(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)
#define _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)
_VARIADIC_EXPAND_1 最终展开就是这个定义了
#define _VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST1, _PAD_LIST1, _RAW_LIST1, _COMMA, X1, X2, X3, X4)
结果全部出来了
#define _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
#define _VARIADIC_EXPAND_3(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST3, _PAD_LIST3, _RAW_LIST3, _COMMA, X1, X2, X3, X4)
#define _VARIADIC_EXPAND_4(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST4, _PAD_LIST4, _RAW_LIST4, _COMMA, X1, X2, X3, X4)
#define _VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST5, _PAD_LIST5, _RAW_LIST5, _COMMA, X1, X2, X3, X4)
这样,我们获取到6(索引0~5)个类似 _VARIADIC_EXPAND_ 的定义。它们最终是宏定义。
_VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
_VARIADIC_EXPAND_1(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
...
_VARIADIC_EXPAND_5(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
我们以索引为 0 的宏定义展开为例。
_VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , ) 展开,那对应的替换就是
// call FUNC(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)
#define _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)
展开后就是
_VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
就是
_CLASS_GET_FUNCTION_IMPL_CALLS(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)
但是这样展开后,我们还是没有看到一个任何类的定义和实现,那继续...
5. 宏 _CLASS_GET_FUNCTION_IMPL_CALLS
#define _CLASS_GET_FUNCTION_IMPL_CALLS( \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4) \
_VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, __cdecl, X2, X3, X4)
通过定义,我们展开 _CLASS_GET_FUNCTION_IMPL_CALLS 宏。还是以索引 0的为例,能得到下面
的定义:
_VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, _TEM_LIST0, _PAD_LIST0, _RAW_LIST0,,__cdecl,X2, X3, X4)
6. 宏_VARIADIC_CALL_OPT_X1
我们来看看这个嵌套在里面的宏.
#define _VARIADIC_CALL_OPT_X1(FUNC, X1, X2, X3, X4, \
CALL_OPT, X6, X7, X8) \
FUNC(X1, X2, X3, X4, CALL_OPT, X6, X7, X8) \
FUNC(X1, X2, X3, X4, __stdcall, X6, X7, X8) \
FUNC(X1, X2, X3, X4, __fastcall, X6, X7, X8)
那实际上展开就是3个如下的宏定义
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __cdecl,X2, X3, X4)
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __stdcall,X2, X3, X4)
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __fastcall,X2, X3, X4)
7. 宏 _CLASS_GET_FUNCTION_IMPL
我们来看 _CLASS_GET_FUNCTION_IMPL 的定义
#define _CLASS_GET_FUNCTION_IMPL( \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4) \
template<class _Ret COMMA LIST(_CLASS_TYPE)> \
struct _Get_function_impl<_Ret CALL_OPT (LIST(_TYPE))> \
{ /* determine type from argument list */ \
typedef _Func_class<_Ret COMMA LIST(_TYPE)> type; \
};
8. 获取原型
结合上面对宏_CLASS_GET_FUNCTION_IMPL的使用,我们能大致获取到下面的定义,我们以
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __cdecl,X2, X3, X4)
为例展:
template<class _Ret _RAW_LIST0(_CLASS_TYPE)> \
struct _Get_function_impl<_Ret __cdecl (_RAW_LIST0(_TYPE))> \
{ /* determine type from argument list */ \
typedef _Func_class<_Ret _RAW_LIST0(_TYPE)> type; \
};
#define _RAW_LIST0(MAP)
#define _VAR_VAL(NUM) _V ## NUM
#define _VAR_TYPE(NUM) _V ## NUM ## _t
#define _CLASS_TYPE(NUM) class _VAR_TYPE(NUM)
template<class _Ret> struct _Get_function_impl<_Ret __cdecl()>
{
typedef _Func_class<_Ret)> type;
};
那
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __stdcall,X2, X3, X4)
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __fastcall,X2, X3, X4)
对应就是
template<class _Ret> struct _Get_function_impl<_Ret __stdcall()>
{
typedef _Func_class<_Ret)> type;
};
template<class _Ret> struct _Get_function_impl<_Ret __fastcall()>
{
typedef _Func_class<_Ret)> type;
};
9. 我们以 _VARIADIC_EXPAND_2 为例来再推导一次
由
_VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
开始,得到
#define _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
可以得到
_CLASS_GET_FUNCTION_IMPL_CALLS(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
进而得到
_VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, _TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA,__cdecl, X2, X3, X4)
继续展开,得到
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__cdecl,X2, X3, X4)
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__stdcall,X2, X3, X4)
_CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__fastcall,X2, X3, X4)
继续展开,得到(先用__cdecl为例)
#define _CLASS_GET_FUNCTION_IMPL( \
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4) \
template<class _Ret _COMMA _RAW_LIST2(_CLASS_TYPE)> \
struct _Get_function_impl<_Ret __cdecl (_RAW_LIST2(_TYPE))> \
{ /* determine type from argument list */ \
typedef _Func_class<_Ret _COMMA _RAW_LIST2(_TYPE)> type; \
};
#define _RAW_LIST2(MAP) MAP(0) _COMMA MAP(1)
#define _RAW_LIST0(MAP)
#define _RAW_LIST2(MAP) MAP(0) _COMMA MAP(1)
#define _VAR_VAL(NUM) _V ## NUM
#define _VAR_TYPE(NUM) _V ## NUM ## _t
#define _CLASS_TYPE(NUM) class _VAR_TYPE(NUM)
#define _TYPE(NUM) _VAR_TYPE(NUM)
全部继续展开,
template<class _Ret , class _V0_t class _V1_t>
struct _Get_function_impl<_Ret __cdecl (_V0_t,_V1_t))>
{
typedef _Func_class<_Ret, _V0_t,_V1_t> type;
};
template<class _Ret , class _V0_t class _V1_t>
struct _Get_function_impl<_Ret __cdecl (_V0_t,_V1_t))>
{
typedef _Func_class<_Ret, _V0_t,_V1_t> type;
};
template<class _Ret , class _V0_t class _V1_t>
struct _Get_function_impl<_Ret __stdcall (_V0_t,_V1_t))>
{
typedef _Func_class<_Ret, _V0_t,_V1_t> type;
};
10. 我们发现,
_VARIADIC_EXPAND_0 对应的是类似这样的定义
template<class _Ret> struct _Get_function_impl<_Ret __stdcall()>
{
typedef _Func_class<_Ret)> type;
};
_VARIADIC_EXPAND_1 对应的是类似这样的定义
template<class _Ret,_V0_t> struct _Get_function_impl<_Ret __stdcall(_V0_t)>
{
typedef _Func_class<_Ret,_V0_t)> type;
};
_VARIADIC_EXPAND_2 对应的是类似这样的定义
template<class _Ret,_V0_t,_V1_t> struct _Get_function_impl<_Ret __stdcall(_V0_t,_V1_t)>
{
typedef _Func_class<_Ret,_V0_t,_V1_t)> type;
};
_VARIADIC_EXPAND_5 对应的是类似这样的定义,5表示有5个参数
template<class _Ret,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t> struct _Get_function_impl<_Ret __stdcall(_V0_t,_V1_t,_V2_t,_V3_t,_V4_t)>
{
typedef _Func_class<_Ret,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t)> type;
};
自此,全部推导结束,也就能理解类是构造的了。
[C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化的更多相关文章
- 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)
本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...
- 【转】Tomcat源代码阅读系列
在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码(Tomcat源代码阅读系列之一) Tomcat总体结构(Tomcat源代码阅读系列之二) Tomcat启动过程(Tomcat ...
- 淘宝数据库OceanBase SQL编译器部分 源代码阅读--生成逻辑计划
淘宝数据库OceanBase SQL编译器部分 源代码阅读--生成逻辑计划 SQL编译解析三部曲分为:构建语法树.生成逻辑计划.指定物理运行计划. 第一步骤,在我的上一篇博客淘宝数据库OceanBas ...
- CI框架源代码阅读笔记3 全局函数Common.php
从本篇開始.将深入CI框架的内部.一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说.全局函数具有最高的载入优先权.因此大多数的框架中BootStrap ...
- Tomcat源代码解析系列
学web也有一段时间了.为了从底层了解web应用在Tomcat中的执行,决定看一下Tomcat的源代码參见<How Tomcat works> 和大牛博客.对大体架构有了一定的了解, ...
- 非常好!!!Linux源代码阅读——环境准备【转】
Linux源代码阅读——环境准备 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/0_prepare.html 目录 Linux 系统环境准备 ...
- 淘宝数据库OceanBase SQL编译器部分 源代码阅读--生成物理查询计划
SQL编译解析三部曲分为:构建语法树,制定逻辑计划,生成物理运行计划. 前两个步骤请參见我的博客<<淘宝数据库OceanBase SQL编译器部分 源代码阅读--解析SQL语法树>& ...
- Java 推荐读物与源代码阅读
Java 推荐读物与源代码阅读 江苏无锡 缪小东 1. Java语言基础 谈到Java ...
- 源码阅读系列:EventBus
title: 源码阅读系列:EventBus date: 2016-12-22 16:16:47 tags: 源码阅读 --- EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的 ...
随机推荐
- go 学习笔记 - sublime text 环境配置
园里已经有了一篇相当不错的配置说明文章,只是现在gosublime不再支持2.x.文章里的操作在sublimetext3 里一样可以使用 文章地址 : http://www.cnblogs.com/s ...
- HTML标签的offset、client、 scroll和currentStyle属性
本文来自:http://www.cnblogs.com/quanhai/archive/2010/04/19/1715231.html offsetHeight = borderTopWidth + ...
- iOS开发-21UINavigationController导航控制器初始化 导航控制器栈的push和pop跳转理解
(1)导航控制器初始化的时候一般都有一个根视图控制器,导航控制器相当于一个栈,里面装的是视图控制器,最先进去的在最下面,最后进去的在最上面.在最上面的那个视图控制器的视图就是这个导航控制器对外展示的界 ...
- uploadify按钮中文乱码问题
uploadify是一款基于jQuery库的上传插件,但很可惜的是无论你怎么设置参数buttonText ,它的中文按钮都会出现乱码的情况,现把出现原因及解决方法总结如下. 那么出现这种的 ...
- xmanager 在 Windows 下远程桌面连接 麒麟
编辑/etc/gdm/custom.conf,添加如下内容: [daemon] RemoteGreeter=/usr/libexec/gdmgreeter 注:“远程登录界面与本地登录界面相同”功能 ...
- 自学Android的第一个小程序(小布局、button点击事件、toast弹出)
因为上班,学习时间有限,昨晚才根据教程写了一个小程序,今天忙里偷闲写一下如何实现的,来加深一下印象. 首先创建一个Android项目, 通过activity_xxx.xml布局文件来添加组件来达到自己 ...
- sql server数据库区分大小写设置
数据库表中字段alter Table TableName 区分大小写 ALTER Column ColumnName VARCHAR(50) COLLATE Chinese_PRC_CS_AS不区分大 ...
- C++ 常见容器
迭代器. 基本介绍(来源于网络):迭代器是一种抽象的概念.能够遍历容器内的 部分/全部 元素.每个迭代器中包含着元素的地址. 它可以将 抽象容器 和 泛型算法 结合起来. 大致原理: 1)迭代器 ...
- oracle 集合定义
集合:是具有相同定义的元素的聚合.Oracle有两种类型的集合: 可变长数组(VARRAY):可以有任意数量的元素,但必须预先定义限制值. 嵌套表:视为表中之表,可以有任意数量的元素,不需要预先定义限 ...
- psycopg2关于undefined symbol: lo_truncate64解决方法
今天,在centos6.5下安装psycopg2,利用Python连接PostgreSQL数据库的时候,出现了一个undefined symbol: lo_truncate6的错误: django.c ...