http://blog.youkuaiyun.com/maray/article/details/11096459
你能实现这样一个函数吗:
- 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
**=======UPDATE=========**
C++11中引入了可变长参数模板,不需要用上面这么丑的方法了。几句话就搞定,而且不用带上说明参数个数的数字了:
- // filename:template.cpp
- #include <iostream>
- using namespace std;
- template<typename T>
- void serialize(T value)
- {
- cout << value << endl;
- }
- template <typename Head, typename... Rail>
- void serialize(Head head, Rail... rail)
- {
- cout << head << ",";
- serialize(rail...);
- }
- int main(int argc, char *argv[])
- {
- serialize(1); // 输出:1
- serialize(1, "hello"); // 输出:1,Hello
- serialize(1, "hello", 'H'); // 输出:1,Hello,H
- return 0;
- }
编译的时候需要试用-std=c++0x或者 -std=gnu++0x
g++ -std=c++0x template.cpp -o template
-
顶