你能实现这样一个函数吗:

  MyType type;
  HisType htype;
  serialize_3(11, type, htype);
  serialize_4(type, htype ,type, htype);
  serialize_4(11, type , htype, htype);

参数类型自由,个数自由,怎么做呢?往下看:

[xiaochu.yh@OB macro]$ cat auto_type.cpp
/*
* (C) 1999-2013 Alibaba Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*
* Version: auto_type.cpp, 09/04/2013 08:02:17 PM Yu Huang Exp $
*
* Author:
* Huang Yu <xiaochu.yh@alipay.com>
* Description:
* auto type match
*
*/ #include <stdio.h> void serialize()
{
return;
} class HisType
{
public:
HisType(const char *i) : value_(i) { }
~HisType() { }
void serialize() const
{
printf("HisType: s(%s)\n", value_);
}
private:
const char *value_;
}; class MyType
{
public:
MyType(int i) : value_(i) { }
~MyType() { }
void serialize() const
{
printf("MyType: f(%d)\n", value_);
}
private:
int value_;
}; void serialize(const int arg0)
{
printf("int: %d\n", arg0);
}
void serialize(const float arg0)
{
printf("float: %f\n", arg0);
} template<typename Arg0>
void serialize(const Arg0 &arg0)
{
arg0.serialize();
} template<typename Arg0>
void serialize_1(const Arg0 &arg0)
{
serialize(arg0);
} #define JOIN(x,y) JOIN2(x,y)
#define JOIN2(x,y) x##y #define DECVAL_1 0
#define DECVAL_2 1
#define DECVAL_3 2
#define DECVAL_4 3
#define DEC_VAL(n) DECVAL_##n // recursively expanding macro
#define ARG_TN0
#define ARG_TN1 typename Arg0
#define ARG_TN2 ARG_TN1, typename Arg1
#define ARG_TN3 ARG_TN2, typename Arg2
#define ARG_TN4 ARG_TN3, typename Arg3 #define ARG_PN0
#define ARG_PN1 const Arg0 & arg0
#define ARG_PN2 ARG_PN1, const Arg1 & arg1
#define ARG_PN3 ARG_PN2, const Arg2 & arg2
#define ARG_PN4 ARG_PN3, const Arg3 & arg3 #define ARG_AN0
#define ARG_AN1 arg0
#define ARG_AN2 ARG_AN1, arg1
#define ARG_AN3 ARG_AN2, arg2
#define ARG_AN4 ARG_AN3, arg3 #define ARG_CN0
#define ARG_CN1 arg0
#define ARG_CN2 arg1
#define ARG_CN3 arg2
#define ARG_CN4 arg3 #define SERIALIZE_DECLARE(NUM_ARG) \
template<JOIN(ARG_TN, NUM_ARG)> \
void JOIN(serialize_, NUM_ARG)(JOIN(ARG_PN, NUM_ARG)) SERIALIZE_DECLARE(2);
SERIALIZE_DECLARE(3);
SERIALIZE_DECLARE(4);
#define SERIALIZE_DEFINE(NUM_ARG) \
template<JOIN(ARG_TN, NUM_ARG)> \
void JOIN(serialize_, NUM_ARG)(JOIN(ARG_PN, NUM_ARG)) \
{ \
JOIN(serialize_, DEC_VAL(NUM_ARG))(JOIN(ARG_AN, DEC_VAL(NUM_ARG))); \
serialize(JOIN(ARG_CN, NUM_ARG)); \
} SERIALIZE_DEFINE(2);
SERIALIZE_DEFINE(3);
SERIALIZE_DEFINE(4); int main()
{
MyType type(4234);
HisType htype("home");
//先来个见面礼, 1是int类型,10.2f是float类型,type是自定义类型
serialize_4(1,10.2f,3, type);
printf("==============\n");
serialize_3(type,11, htype); // <== 注意下面的参数个数,以及参数顺序,完全自由!
printf("==============\n");
serialize_3(11 ,type, htype);
printf("==============\n");
serialize_3(htype ,type, htype);
printf("==============\n");
return 0;
}

编译运行结果:

[xiaochu.yh@OB macro]$ g++ auto_type.cpp
[xiaochu.yh@OB]$ ./a.out
int: 1
float: 10.200000
int: 3
MyType: f(4234)
==============
MyType: f(4234)
int: 11
HisType: s(home)
==============
int: 11
MyType: f(4234)
HisType: s(home)
==============
HisType: s(home)
MyType: f(4234)
HisType: s(home)
==============

该技术是从曲山同学的代码中学习来的,曲山对宏的运用真是炉火纯青!这里最神奇的就是下面一段代码,至今不明:

#define JOIN(x,y) JOIN2(x,y)
#define JOIN2(x,y) x##y

JOIN和JOIN2不是等价的吗?不过还真不是。如果只写JOIN2,在宏展开阶段会有比较诡异的事情发生。不信你试试。但是为什么呢?我也不知道。@曲山,求助啊~~

更全面的代码见OceanBase源码oceanbase/src/common/ob_rpc_stub.h和oceanbase/src/common/ob_rpc_macros.h

=============================================

UPDATE:

这篇帖子发到了内网,得到了@探晴同学指点,加上@元启 同学的解释,基本弄明白了JOIN的机制。

原因的确很简单。 
#define MY_VALUE 2 
#define JOIN(A,B) A##B
JOIN(hello, world)的输出结果就是 helloworld,
JOIN(MY_VALUE, b)的输出结果就是 MY_VALUEb。尽管MY_VALUE是个宏,你期待它展开成2b。

如何成为一个2b呢? 这么做:
#define JOIN(a, b) JOIN_EXPAND_PARAM(a,b)
#define JOIN_EXPAND_PARAM(a,b) a##b

JOIN(MY_VALUE, b)的展开过程是:
1. JOIN(MY_VALUE, b)展开成 JOIN_EXPAND_PARAM(2, b)
2. JOIN_EXPAND_PARAM(2, b) 展开成 2b

这句话:Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens.

参考: http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html

介绍一个C++奇巧淫技的更多相关文章

  1. LLDB奇巧淫技

    打印视图层级 这个相信很多人都会了,是ta是ta就是ta recursiveDescription 用法大概就是如下 123 po [self.view recursiveDescription] p ...

  2. octave之奇巧淫技向量化计算实现寻找样本点所属聚类下标

    前面有文章提到过,K-means算法,第一步骤是找出样本点的的所属聚类.下面用两种方式实现,一种是普通的循环,一种是完全向量化计算. 假设 : X 是m×n样本矩阵,其每一行是一个样本,m表示样本数目 ...

  3. iOS开发的一些奇巧淫技(转载)

    iOS开发的一些奇巧淫技 http://www.cocoachina.com/ios/20141229/10783.html iOS开发的一些奇巧淫技2 http://www.cocoachina.c ...

  4. [异常解决] 奇巧淫技——VirtualBox中的linux无显示启动,并在win7上远程控制

    楼主是资深技术宅(癖),由于感觉手上的老笔记本太卡,遂狠心买了个性能至强的主机同时配了个投影仪(满足躺着打代码的意淫场景).但是体验了大概一个月发现还是坐着打代码舒服,但是如下图坐着打代码总是要抬头看 ...

  5. iOS开发的一些奇巧淫技

    TableView不显示没内容的Cell怎么办? 类似这种,我不想让下面那些空的显示. 很简单. self.tableView.tableFooterView = [[UIView alloc] in ...

  6. C基础 那些年用过的奇巧淫技

    引言 - 为寻一颗明星 为要寻一颗明星 徐志摩 1924年12月1日<晨报六周年纪念增刊> 我骑著一匹拐腿的瞎马, 向著黑夜里加鞭:—— 向著黑夜里加鞭, 我跨著一匹拐腿的瞎马.// 我冲 ...

  7. iOS开发的一些奇巧淫技2

    能不能只用一个pan手势来代替UISwipegesture的各个方向? - (void)pan:(UIPanGestureRecognizer *)sender { typedef NS_ENUM(N ...

  8. Windows的奇巧淫技(为什么GIF显示不出来??)

    谁的电脑里没点小秘密?东藏西藏到最后自己都找不到了有木有?今天教大家个隐藏文件的高招: 将任意文件隐藏到图片中!怎么样?再也不用建什么「马列主义哲学」的文件夹啦!

  9. powerdesigner奇淫技

    在日常开发中数据库的设计常常需要建立模型,而powerdesigner是个不错的选择.但很多时候用powerdesigner生成模型后再去创建表结构,会觉得烦和别扭.那么能不能数据库表建好后再生成模型 ...

随机推荐

  1. hdu 4861 Couple doubi(数论)

    题目链接:hdu 4861 Couple doubi 题目大意:两个人进行游戏,桌上有k个球,第i个球的值为1i+2i+⋯+(p−1)i%p,两个人轮流取,假设DouBiNan的值大的话就输出YES, ...

  2. Swift - iOS中各种视图控制器(View Controller)的介绍

    在iOS中,不同的视图控制器负责不同的功能,采用不同的风格向用户呈现信息.下面对各个视图控制器做个总结: 1,标准视图控制器 - View Controller 这个控制器只是用来呈现内容.通常会用来 ...

  3. Windows下用WinSCP传输数据到Linux上

    Scenario:最近公司做的一个项目,UI部分我是使用python在编译时做localization的,是linux下运行的,但是开发是在windows下进行的每次编译后都要手动通过WinSCP这个 ...

  4. 修改OpenSSL默认编译出的动态库文件名称

    在 Windows 平台上调用动态链接库 dll 文件时,有两种方式:a) 隐式的加载时链接:使用 *.lib (导入库)文件,在 IDE 的链接器相关设置中加入导入库 lib 文件的名称,或在程序中 ...

  5. 终于懂了:Delphi消息的Result完全是生造出来的,不是Windows消息自带的(Delphi对Windows编程体系的改造越大,学习收获就越大)——消息是否继续传递就看这个Result

    Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样. t ...

  6. 稳定婚姻问题和Gale-Shapley算法(转)

    什么是算法?每当有人问作者这样的问题时,他总会引用这个例子:假如你是一个媒人,有若干个单身男子登门求助,还有同样多的单身女子也前来征婚.如果你已经知道这些女孩儿在每个男孩儿心目中的排名,以及男孩儿们在 ...

  7. HDU 3468 BFS+二分匹配

    九野的博客,转载请注明出处 http://blog.csdn.net/acmmmm/article/details/10966383 开始建图打搓了,参考了大牛的题解打的版本比较清爽,后来改的基本雷同 ...

  8. 来推荐个免费的PPT演示工具--ZohoShowTime

    事实上这个不算新产品了,这次是做了一些大的改进.上次在Zoho的全球用户大会上,全程演讲都是用的这个工具.Zoho这点非常好啊.自己的产品自己带头用.个人认为它最大的用处就是.离得远的观众能够在自己的 ...

  9. Spring Uploading Files

    1,在servlet-dispatcher.xml中添加代码 <bean id="multipartResolver" class="org.springframe ...

  10. Web前端,高性能优化

    高性能HTML 一.避免使用iframe iframe也叫内联frame,可将一个HTML文档嵌入另一个HTML文档中. iframe的好处是,嵌入的文档独立于父文档,通常也借此使浏览器模拟多线程.缺 ...