介绍一个C++奇巧淫技

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

 

  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 <[email protected]>

 * 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++)